2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 // Sprite Model Plugin
25 // Code by Hydra aka Dominic Clifton
27 // Based on MD3Model source code by SPoG
38 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.
40 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).
45 Implemented as a model module, without any ISelect stuff.
47 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.
51 baseq3/scripts/entities.def
52 ===========================
54 \/\*QUAKED ammo_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) SUSPENDED
56 -------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
57 model="sprites/powerups/ammo/bfgam.bmp"\*\/
60 valve/scripts/halflife.fgd
61 ==========================
63 @PointClass iconsprite("sprites/lightbulb.spr") base(Target, Targetname, Light) = light : "Invisible lightsource"
68 What image formats are supported ?
69 ----------------------------------
71 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.
77 - Created an inital implementation of a sprite model plugin.
78 According to the powers that be, it seems creating a model
80 It works ok, but there is no way to attach models (sprites if you will)
81 to non-fixedsize entities (like func_bombtarget)
82 Also, I can't get the alpha map stuff right so I had to invert the alpha
83 mask in the spr loader so that 0xff = not drawn pixel.
86 - Updated to coincide with Radiant 1.3.5 test builds. Also, I made sure it worked
87 under quake3 and it does.
95 * make sprites always face the camera (is this done in camwindow.cpp ?)
96 but only if the entity model doesn't have "angle" keys. At the moment
97 it's better to rotate the model with the angles.
99 * maybe add an option to scale the sprites in the prefs ?
101 * maybe convert to a new kind of class not based on model.
103 * allow sprites on non-fixedsize ents
105 * fix reversed alpha map in spr loader
106 -> is this actually broken?
108 * allow an entity to have multiple models (e.g .md3 and a sprite model)
109 and allow the user to toggle either models on or off.
111 * dynamically add the api's depending on what image loading modules are
112 supported by radiant.
113 Currently, we hard code to the list in "supportedmodelformats" (see below)
114 but, all these extensions are stripped when the actual image is loaded.
115 current the bit of code that decided what model api to use needs reworking
116 as it decides by looking at the extension of the model name, when in fact
117 we don't even need an extension.
119 Previously the code fell though to use this model as the default model
120 plugin, but that also has issues.
122 what it means is, in the .def files you must specify an image filename
123 that has one of the extensions listed below, but in actual fact radiant
124 will use any available image module to load the image.
127 e.g. you could use a model name of "sprites/target_speaker.tga" and have
128 a file called sprites/target_speaker.png and it would be correctly loaded
129 even if it not listed below in "supportedmodelformats".
131 So, currently in the .def files you can just use the name
132 "sprites/target_speaker.spr" and it will load the file
133 from "sprites/target_speaker.*" which is what I propose anyone creating image sets for Q3/Wolf/etc does.
138 // =============================================================================
142 _QERFuncTable_1 g_FuncTable;
143 _QERQglTable g_QglTable;
144 _QERShadersTable g_ShadersTable;
146 // =============================================================================
147 // plugin implementation
149 static const char *PLUGIN_NAME = "Sprite Model loading module";
151 static const char *PLUGIN_COMMANDS = "About...";
153 static const char *PLUGIN_ABOUT = "Sprite Model loading module v0.2 for GTKRadiant\n\n"
156 char *supportedmodelformats[] = {"spr","bmp","tga","jpg","hlw",NULL}; // NULL is list delimiter
158 static void add_model_apis(CSynapseClient& client)
161 for (ext = supportedmodelformats; *ext != NULL; ext++)
163 client.AddAPI(MODEL_MAJOR, *ext, sizeof(_QERPlugModelTable));
167 static bool model_is_supported(const char* extension)
170 for (ext = supportedmodelformats; *ext != NULL; ext++)
172 if (stricmp(extension,*ext)==0)
178 void init_filetypes()
181 for (ext = supportedmodelformats; *ext != NULL; ext++)
183 GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t("sprite", *ext));
187 extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget)
189 init_filetypes(); // see todo list above.
190 return (char *) PLUGIN_NAME;
193 extern "C" const char* QERPlug_GetName ()
195 return (char *) PLUGIN_NAME;
198 extern "C" const char* QERPlug_GetCommandList ()
200 return (char *) PLUGIN_COMMANDS;
203 extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush)
205 // NOTE: this never happens in a module
206 if(!strcmp(p, "About..."))
207 g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL);
210 // =============================================================================
213 CSynapseServer* g_pSynapseServer = NULL;
214 CSynapseClientModel g_SynapseClient;
216 extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer)
218 if (strcmp(version, SYNAPSE_VERSION))
220 Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version);
223 g_pSynapseServer = pServer;
224 g_pSynapseServer->IncRef();
225 Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());
227 add_model_apis(g_SynapseClient); // see todo list above.
229 g_SynapseClient.AddAPI( PLUGIN_MAJOR, "sprite", sizeof( _QERPluginTable ) );
230 g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable );
231 g_SynapseClient.AddAPI( QGL_MAJOR, NULL, sizeof( g_QglTable ), SYN_REQUIRE, &g_QglTable );
232 g_SynapseClient.AddAPI( SHADERS_MAJOR, "*", sizeof( g_ShadersTable ), SYN_REQUIRE, &g_ShadersTable );
234 return &g_SynapseClient;
237 bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI)
239 if (!strcmp(pAPI->major_name, MODEL_MAJOR))
241 _QERPlugModelTable* pTable= static_cast<_QERPlugModelTable*>(pAPI->mpTable);
243 if (model_is_supported(pAPI->minor_name)) // see todo list above.
245 pTable->m_pfnLoadModel = &LoadSpriteModel;
249 else if (!strcmp(pAPI->major_name, PLUGIN_MAJOR))
251 _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable);
253 pTable->m_pfnQERPlug_Init = QERPlug_Init;
254 pTable->m_pfnQERPlug_GetName = QERPlug_GetName;
255 pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList;
256 pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch;
260 Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());
266 const char* CSynapseClientModel::GetInfo()
268 return "Sprite Model module built " __DATE__ " " RADIANT_VERSION;
271 const char* CSynapseClientModel::GetName()