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