2 This file is part of the 3dengfx demo system.
4 Copyright (c) 2004, 2005 John Tsiombikas <nuclear@siggraph.org>
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.
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.
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
21 #include "3dengfx_config.h"
28 #include "3dengfx/3dengfx.hpp"
29 #include "common/err_msg.h"
32 static bool str_to_color(const char *str, Color *col);
35 void dsys::radial_blur(Texture *tex, float ammount, const Vector2 &origin, bool additive) {
36 Vector2 c1(0.0f, 0.0f), c2(1.0f, 1.0f);
38 set_alpha_blending(true);
40 set_blend_func(BLEND_SRC_ALPHA, BLEND_ONE);
42 set_blend_func(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
46 int quad_count = (int)(ammount * 20.0f);
47 float dscale = (ammount - 1.0f) / (float)quad_count;
49 for(int i=0; i<quad_count; i++) {
50 Vector2 v1 = c1, v2 = c2;
59 float alpha = (float)((quad_count-1) - i) / (float)quad_count;
60 dsys::overlay(tex, v1, v2, Color(1.0f, 1.0f, 1.0f, alpha), 0, false);
64 set_alpha_blending(false);
67 void dsys::dir_blur(Texture *tex, float ammount, int dir) {
68 Vector2 c1(0.0f, 1.0f), c2(1.0f, 0.0f);
71 int quad_count = (int)(ammount * 100.0f);
72 float offs_inc = ammount / (float)(quad_count/2);
74 for(int i=0; i<quad_count/2; i++) {
75 Vector2 off_vec = dir == BLUR_DIR_X ? Vector2(offs, 0) : Vector2(0, offs);
77 float alpha = 1.0f - offs / ammount;
78 dsys::overlay(tex, c1 + off_vec, c2 + off_vec, Color(1.0f, 1.0f, 1.0f, alpha));
79 //dsys::overlay(tex, c1 - off_vec, c2 - off_vec, Color(1.0f, 1.0f, 1.0f, alpha));
85 static Vector2 *blur_pos;
88 void dsys::blur(Texture *tex, float ammount, bool additive) {
91 set_alpha_blending(true);
93 set_blend_func(BLEND_SRC_ALPHA, BLEND_ONE);
95 set_blend_func(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
98 int quad_count = (int)(ammount * 700.0f);
100 if(quad_count != pos_count) {
101 if(blur_pos) delete [] blur_pos;
102 blur_pos = new Vector2[quad_count];
104 for(int i=0; i<quad_count; i++) {
105 blur_pos[i] = Vector2(frand(1.0f) - 0.5f, frand(1.0f) - 0.5f);
106 blur_pos[i] *= ammount;
108 pos_count = quad_count;
111 for(int i=0; i<quad_count; i++) {
112 float dist = blur_pos[i].length_sq();
113 float alpha = 1.0f / dist;
114 dsys::overlay(tex, Vector2(0, 0) + blur_pos[i], Vector2(1, 1) + blur_pos[i], Color(1.0f, 1.0f, 1.0f, alpha), false);
117 set_alpha_blending(false);
121 void dsys::overlay(Texture *tex, const Vector2 &corner1, const Vector2 &corner2, const Color &color, GfxProg *pprog, bool handle_blending) {
122 glMatrixMode(GL_MODELVIEW);
126 float aspect = (float)fxwt::screenx / fxwt::screeny;
127 float offs = (1.333333333f - aspect) / 2.0f;
128 glMatrixMode(GL_PROJECTION);
131 glOrtho(offs, 1.0 - offs, 1.0, 0.0, 0.0, 1.0);
134 set_zbuffering(false);
135 set_backface_culling(false);
136 if(handle_blending) {
137 set_alpha_blending(true);
138 set_blend_func(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
142 enable_texture_unit(0);
143 disable_texture_unit(1);
144 set_texture_unit_color(0, TOP_REPLACE, TARG_TEXTURE, TARG_COLOR);
145 set_texture_unit_alpha(0, TOP_MODULATE, TARG_TEXTURE, TARG_COLOR);
146 set_texture_coord_index(0, 0);
148 set_texture_addressing(0, TEXADDR_CLAMP, TEXADDR_CLAMP);
150 for(int i=0; i<4; i++) {
151 if(tex == dsys::tex[i]) {
152 glMatrixMode(GL_TEXTURE);
153 load_matrix_gl(dsys::tex_mat[i]);
160 set_gfx_program(pprog);
164 glColor4f(color.r, color.g, color.b, color.a);
165 glTexCoord2f(0.0f, 1.0f);
166 glVertex3f(corner1.x, corner1.y, -0.5);
167 glTexCoord2f(1.0f, 1.0f);
168 glVertex3f(corner2.x, corner1.y, -0.5);
169 glTexCoord2f(1.0f, 0.0f);
170 glVertex3f(corner2.x, corner2.y, -0.5);
171 glTexCoord2f(0.0f, 0.0f);
172 glVertex3f(corner1.x, corner2.y, -0.5);
180 for(int i=0; i<4; i++) {
181 if(tex == dsys::tex[i]) {
182 glMatrixMode(GL_TEXTURE);
183 load_matrix_gl(Matrix4x4::identity_matrix);
187 set_texture_addressing(0, TEXADDR_WRAP, TEXADDR_WRAP);
188 disable_texture_unit(0);
190 if(handle_blending) set_alpha_blending(false);
191 set_backface_culling(true);
192 set_zbuffering(true);
195 glMatrixMode(GL_PROJECTION);
197 glMatrixMode(GL_MODELVIEW);
201 void dsys::negative(const Vector2 &corner1, const Vector2 &corner2) {
202 set_alpha_blending(true);
203 set_blend_func(BLEND_ONE_MINUS_DST_COLOR, BLEND_ZERO);
204 dsys::overlay(0, corner1, corner2, Color(1.0f, 1.0f, 1.0f, 1.0f), 0, false);
205 set_alpha_blending(false);
208 void dsys::flash(unsigned long time, unsigned long when, unsigned long dur, const Color &col) {
209 long start = when - dur/2;
210 long end = when + dur/2;
212 if((long)time >= start && (long)time < end) {
213 scalar_t t = (scalar_t)time / 1000.0;
214 scalar_t dt = (scalar_t)dur / 1000.0;
215 scalar_t wt = (scalar_t)when / 1000.0;
216 scalar_t half_dt = dt / 2.0;
218 scalar_t alpha = cos(pi * (t - wt) / half_dt);
220 dsys::overlay(0, Vector3(0,0), Vector3(1,1), Color(col.r, col.g, col.b, alpha));
226 // ------------- Image Effect manager --------------
229 using namespace dsys;
231 static list<ImageFx*> fx_list;
233 void dsys::add_image_fx(ImageFx *fx) {
234 fx_list.push_back(fx);
237 void dsys::remove_image_fx(ImageFx *fx) {
238 fx_list.erase(find(fx_list.begin(), fx_list.end(), fx));
241 void dsys::apply_image_fx(unsigned long time) {
242 list<ImageFx*>::iterator iter = fx_list.begin();
244 while(iter != fx_list.end()) {
245 (*iter++)->apply(time);
250 // -------------- Image Effect class --------------
257 ImageFx::~ImageFx() {}
259 bool ImageFx::parse_script_args(const char **args) {
262 if(!args[0] || (t = str_to_time(args[0])) == -1) {
266 if(!args[1] || (d = str_to_time(args[1])) == -1) {
275 void ImageFx::set_time(unsigned long time) {
279 void ImageFx::set_duration(unsigned long dur) {
284 // ------------- Negative (inverse video) effect ---------------
286 FxNegative::~FxNegative() {}
288 void FxNegative::apply(unsigned long time) {
289 if(time < this->time || time > this->time + duration) return;
294 // ------------ Screen Flash -------------
296 FxFlash::~FxFlash() {}
299 color = Color(1.0, 1.0, 1.0);
302 bool FxFlash::parse_script_args(const char **args) {
303 if(!ImageFx::parse_script_args(args)) {
308 if(!str_to_color(args[2], &color)) return false;
314 void FxFlash::set_color(const Color &col) {
318 void FxFlash::apply(unsigned long time) {
319 flash(time, this->time, duration, color);
323 // ------------- Fade in/out -------------
326 color1 = Color(0.0, 0.0, 0.0);
327 color2 = Color(1.0, 1.0, 1.0);
333 bool FxFade::parse_script_args(const char **args) {
334 if(!ImageFx::parse_script_args(args)) {
339 if(!str_to_color(args[2], &color1)) return false;
342 if(args[3] && !(args[3][0] == '0' && args[3][1] == 0)) {
343 // texture register? (t0, t1, t2, t3)
344 if(args[3][0] == 't' && isdigit(args[3][1]) && !args[3][2]) {
345 int reg = args[3][1] - '0';
346 if(reg > 3) return false;
347 tex1 = dsys::tex[reg];
348 } else { // or a texture from file?
349 if(!(tex1 = get_texture(args[3]))) {
356 if(!str_to_color(args[4], &color2)) return false;
359 if(args[5] && !(args[5][0] == '0' && args[5][1] == 0)) {
360 // texture register? (t0, t1, t2, t3)
361 if(args[5][0] == 't' && isdigit(args[5][1]) && !args[5][2]) {
362 int reg = args[5][1] - '0';
363 if(reg > 3) return false;
364 tex2 = dsys::tex[reg];
365 } else { // or a texture from file?
366 if(!(tex2 = get_texture(args[5]))) {
375 void FxFade::apply(unsigned long time) {
376 if(time >= this->time && time < this->time + duration) {
377 float fsec = (float)(time - this->time) / 1000.0;
378 float t = fsec / ((float)duration / 1000.0);
381 set_texture(0, tex1);
382 enable_texture_unit(0);
386 set_texture(1, tex2);
387 enable_texture_unit(1);
389 set_texture_constant(1, t);
390 set_texture_unit_color(1, TOP_LERP, TARG_PREV, TARG_TEXTURE, TARG_CONSTANT);
393 set_alpha_blending(true);
394 set_blend_func(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
397 Color col = color1 + (color2 - color1) * t;
398 col.a = color1.a + (color2.a - color1.a) * t;
400 draw_scr_quad(Vector2(0, 0), Vector2(1, 1), col);
403 set_alpha_blending(false);
405 if(tex1) disable_texture_unit(0);
406 if(tex2) disable_texture_unit(1);
410 // ------------ Image Overlay ------------
413 FxOverlay::FxOverlay() {
418 FxOverlay::~FxOverlay() {
422 bool FxOverlay::parse_script_args(const char **args) {
423 if(!ImageFx::parse_script_args(args)) {
426 if(!args[2]) return false;
428 // texture register? (t0, t1, t2, t3)
429 if(args[2][0] == 't' && isdigit(args[2][1]) && !args[2][2]) {
430 int reg = args[2][1] - '0';
431 if(reg > 3) return false;
432 tex = dsys::tex[reg];
433 } else { // or a texture from file?
434 if(!(tex = get_texture(args[2]))) {
439 // check if a shader is specified
441 Shader sdr = get_shader(args[3], PROG_PIXEL);
443 error("failed loading shader %s", args[3]);
447 shader = new GfxProg(0, sdr);
453 void FxOverlay::set_texture(Texture *tex) {
457 void FxOverlay::set_shader(GfxProg *sdr) {
461 void FxOverlay::apply(unsigned long time) {
462 if(time >= this->time && time < this->time + duration) {
464 float fsec = (float)(time - this->time) / 1000.0;
465 shader->set_parameter("time", fsec);
467 float t = fsec / ((float)duration / 1000.0f);
468 shader->set_parameter("t", t);
470 float ease = (t < 0.25 || t >= 0.75) ? fabs(sin(t * 2.0 * pi)) : 1.0;
471 shader->set_parameter("ease", ease);
473 float ease_sin = sin(t * pi);
474 shader->set_parameter("ease_sin", ease_sin);
476 overlay(tex, Vector2(0, 0), Vector2(1, 1), Color(1, 1, 1), shader);
482 // just a little helper function to get a color out of an <r,g,b> string
483 static bool str_to_color(const char *str, Color *col) {
485 if(*str++ != '<') return false;
486 if(!isdigit(*str) && *str != '.') return false;
489 while(isdigit(*str) || *str == '.') str++;
490 if(*str++ != ',') return false;
493 if(!isdigit(*str) && *str != '.') return false;
496 while(isdigit(*str) || *str == '.') str++;
497 if(*str++ != ',') return false;
500 if(!isdigit(*str) && *str != '.') return false;
503 while(isdigit(*str) || *str == '.') str++;
506 return *str == '>' ? true : false;
510 if(!isdigit(*++str) && *str != '.') return false;
513 while(isdigit(*str) || *str == '.') str++;
514 return *str == '>' ? true : false;