added 3dengfx into the repo, probably not the correct version for this
[summerhack] / src / 3dengfx / src / dsys / dsys.cpp
1 /*
2 This file is part of 3dengfx demosystem.
3
4 Copyright (c) 2004, 2005 John Tsiombikas <nuclear@siggraph.org>
5
6 This program 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 This program 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 this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "3dengfx_config.h"
22
23 #include <iostream>
24 #include <algorithm>
25 #include <string>
26 #include <map>
27 #include "dsys.hpp"
28 #include "part.hpp"
29 #include "fx.hpp"
30 #include "cmd.hpp"
31 #include "script.h"
32 #include "3dengfx/3dengfx.hpp"
33 #include "n3dmath2/n3dmath2.hpp"
34 #include "common/timer.h"
35 #include "common/err_msg.h"
36
37 #if defined(__unix__) || defined(unix)
38 #include <unistd.h>
39 #include <sys/stat.h>
40 #endif  // unix
41
42 using namespace dsys;
43 using namespace std;
44
45 static int execute_script(DemoScript *ds, unsigned long time);
46
47 Texture *dsys::tex[4];
48 unsigned int dsys::rtex_size_x, dsys::rtex_size_y;
49 Matrix4x4 dsys::tex_mat[4];
50
51 typedef map<string, Part*> PartTree;
52 static PartTree parts;
53 static PartTree running;
54
55 static ntimer timer;
56
57 static char script_fname[256];
58 static DemoScript *ds;
59
60 static bool demo_running = false;
61 static bool seq_render = false;
62 static unsigned long seq_time, seq_dt;
63
64 static int best_tex_size(int n) {
65         int i;
66         for(i=64; i<2048; i*=2) {
67                 if(i*2 > n) return i;
68         }
69
70         return 2048;
71 }
72
73 bool dsys::init() {
74         int scrx = get_graphics_init_parameters()->x;
75         int scry = get_graphics_init_parameters()->y;
76
77         int next_size_x, next_size_y;
78         
79         rtex_size_x = best_tex_size(scrx - 1);
80         rtex_size_y = best_tex_size(scry - 1);
81         
82         next_size_x = rtex_size_x * 2;
83         next_size_y = rtex_size_y * 2;
84                 
85         info("allocating dsys render targets:");
86
87         //if (!engfx_state::sys_caps.non_power_of_two_textures)
88         //{
89                 // make a high-res texture and 3 low-res
90                 for(int i=0; i<4; i++) {
91                         int x = (i > 1) ? rtex_size_x : next_size_x;
92                         int y = (i > 1) ? rtex_size_y : next_size_y;
93                         tex[i] = new Texture(x, y);
94                         info("  %d - %dx%d", i, x, y);
95                 }
96
97                 tex_mat[0].set_scaling(Vector3((float)scrx / (float)next_size_x, (float)scry / (float)next_size_y, 1));
98                 tex_mat[1].set_scaling(Vector3((float)scrx / (float)next_size_x, (float)scry / (float)next_size_y, 1));
99
100                 tex_mat[2] = Matrix4x4::identity_matrix;
101                 tex_mat[3] = Matrix4x4::identity_matrix;
102         /*}
103         else
104         {
105                 for (int i=0; i<4; i++)
106                 {
107                         tex[i] = new Texture(scrx, scry);
108                         info("  %d - %dx%d", i, scrx, scry);
109                         tex_mat[i] = Matrix4x4::identity_matrix;
110                 }
111         }*/
112
113         strcpy(script_fname, "demoscript");
114
115         cmd::register_commands();
116         
117         return true;
118 }
119
120 void dsys::clean_up() {
121         for(int i=0; i<4; i++) {
122                 if(tex[i]) delete tex[i];
123                 tex[i] = 0;
124         }
125 }
126
127 void dsys::use_rt_tex(RenderTarget rt) {
128         set_texture(0, tex[rt]);
129         set_matrix(XFORM_TEXTURE, tex_mat[rt]);
130 }
131
132 void dsys::set_demo_script(const char *fname) {
133         strcpy(script_fname, fname);
134 }
135
136
137 unsigned long dsys::get_demo_time() {
138         return seq_render ? seq_time : timer_getmsec(&timer);
139 }
140
141
142 void dsys::add_part(Part *part) {
143         if(!part->get_name()) {
144                 error("dsys::add_part - trying to add a nameless part...");
145                 return;
146         }
147         parts[string(part->get_name())] = part;
148 }
149
150 void dsys::remove_part(Part *part) {
151         PartTree::iterator iter = parts.find(part->get_name());
152         parts.erase(iter);
153 }
154
155 void dsys::start_part(Part *part) {
156         running[part->get_name()] = part;
157         part->start();
158 }
159
160 void dsys::stop_part(Part *part) {
161         part->stop();
162         PartTree::iterator iter = running.find(part->get_name());
163         if(iter != running.end()) {
164                 running.erase(iter);
165         } else {
166                 error("stop_part() called for unknown part: %s\n", part->get_name());
167         }
168 }
169
170 Part *dsys::get_part(const char *pname) {
171         PartTree::iterator iter = parts.find(pname);
172         return iter != parts.end() ? iter->second : 0;
173 }
174
175 Part *dsys::get_running(const char *pname) {
176         PartTree::iterator iter = running.find(pname);
177         return iter != running.end() ? iter->second : 0;
178 }
179
180
181 bool dsys::start_demo() {
182         if(!(ds = open_script(script_fname))) {
183                 return false;
184         }
185         demo_running = true;
186         timer_reset(&timer);
187         timer_start(&timer);
188         return true;
189 }
190
191 #define PATH_MAX 2048
192 static char curr_dir[PATH_MAX];
193
194 bool dsys::render_demo(int fps, const char *out_dir) {
195         if(!(ds = open_script(script_fname))) {
196                 return false;
197         }
198         
199 #if defined(__unix__) || defined(unix)
200         // change to the specified directory
201         getcwd(curr_dir, PATH_MAX);
202
203         struct stat sbuf;
204         if(stat(out_dir, &sbuf) == -1) {
205                 mkdir(out_dir, 0770);
206         }       
207         
208         chdir(out_dir);
209 #endif  // __unix__
210
211         demo_running = true;
212         seq_render = true;
213         seq_time = 0;
214         seq_dt = 1000 / fps;
215
216         return true;
217 }
218
219 void dsys::end_demo() {
220 #if defined(__unix__) || defined(unix)
221         if(seq_render) {
222                 chdir(curr_dir);
223         }
224 #endif  // unix
225         
226         if(demo_running) {
227                 close_script(ds);
228                 demo_running = false;
229         }
230 }
231
232
233 static void update_node(const pair<string, Part*> &p) {
234         p.second->update_graphics();
235 }
236
237 int dsys::update_graphics() {
238         if(!demo_running) {
239                 return 1;
240         }
241
242         unsigned long time = get_demo_time();
243
244         int res;
245         while((res = execute_script(ds, time)) != 1) {
246                 if(res == EOF) {
247                         end_demo();
248                         return -1;
249                 }
250         }
251
252         // update graphics
253         clear(Color(0.0f, 0.0f, 0.0f));
254         clear_zbuffer_stencil(1.0f, 0);
255         
256         for_each(running.begin(), running.end(), update_node);
257
258         // apply any post effects
259         apply_image_fx(time);
260
261         if(seq_render) {
262                 screen_capture();
263                 seq_time += seq_dt;
264         }
265                 
266         flip();
267         return 0;
268 }
269
270 static int execute_script(DemoScript *ds, unsigned long time) {
271         DemoCommand command;
272         
273         int res = get_next_command(ds, &command, time);
274         if(res == EOF || res == 1) {
275                 return res;
276         }
277
278         if(!cmd::command(command.type, command.argv[0], command.argv + 1)) {
279                 error("error in demoscript command execution!");
280         }
281         free_command(&command);
282
283         return demo_running ? 0 : -1;
284 }
285