Merge commit '48410b113dd2036e69dbf723a39ec9af02fc9b12'
[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   {
126     client.AddAPI(MODEL_MAJOR, *ext, sizeof(_QERPlugModelTable));
127   }
128 }
129
130 static bool model_is_supported(const char* extension)
131 {
132   char **ext;
133   for (ext = supportedmodelformats; *ext != NULL; ext++)
134   {
135     if (stricmp(extension,*ext)==0)
136       return true;
137   }
138   return false;
139 }
140
141 void init_filetypes()
142 {
143   char **ext;
144   for (ext = supportedmodelformats; *ext != NULL; ext++)
145   {
146     GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t("sprite", *ext));
147   }
148 }
149
150 extern CSynapseServer* g_pSynapseServer;
151
152 class CSynapseClientModel : public CSynapseClient
153 {
154 public:
155   // CSynapseClient API
156   bool RequestAPI(APIDescriptor_t *pAPI);
157   const char* GetInfo();
158   const char* GetName();
159
160   CSynapseClientModel() { }
161   virtual ~CSynapseClientModel() { }
162
163   bool OnActivate()
164   {
165     init_filetypes(); // see todo list above.
166     return true;
167   }
168 };
169
170 CSynapseServer* g_pSynapseServer = NULL;
171 CSynapseClientModel g_SynapseClient;
172     
173 extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer)
174 {
175   if (strcmp(version, SYNAPSE_VERSION))
176   {
177     Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version);
178     return NULL;
179   }
180   g_pSynapseServer = pServer;
181   g_pSynapseServer->IncRef();
182   Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());
183
184   add_model_apis(g_SynapseClient); // see todo list above.
185
186   g_SynapseClient.AddAPI( PLUGIN_MAJOR, "sprite", sizeof( _QERPluginTable ) );
187   g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable );
188   g_SynapseClient.AddAPI( QGL_MAJOR, NULL, sizeof( g_QglTable ), SYN_REQUIRE, &g_QglTable );
189   g_SynapseClient.AddAPI( SHADERS_MAJOR, "*", sizeof( g_ShadersTable ), SYN_REQUIRE, &g_ShadersTable );
190
191   return &g_SynapseClient;
192 }
193
194 bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI)
195 {
196   if (!strcmp(pAPI->major_name, MODEL_MAJOR))
197   {
198     _QERPlugModelTable* pTable= static_cast<_QERPlugModelTable*>(pAPI->mpTable);
199
200     if (!strcmp(pAPI->minor_name, "sprite"))
201     {
202       pTable->m_pfnLoadModel = &LoadSpriteModel;
203       return true;
204     }
205   }
206
207   Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());
208   return false;
209 }
210
211 #include "version.h"
212
213 const char* CSynapseClientModel::GetInfo()
214 {
215   return "Sprite Model module built " __DATE__ " " RADIANT_VERSION;
216 }
217
218 const char* CSynapseClientModel::GetName()
219 {
220   return "sprite";
221 }