📄 background.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / 3D rendering module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "render3d_nodes.h"/*for background textures - the offset is to prevent lines on cube map edges*/#define PLANE_HSIZE FLT2FIX(0.5025f)#define PLANE_HSIZE_LOW FLT2FIX(0.5f)static Bool back_use_texture(MFURL *url){ if (!url->count) return 0; if (url->vals[0].OD_ID > 0) return 1; if (url->vals[0].url && strlen(url->vals[0].url)) return 1; return 0;}static void UpdateBackgroundTexture(GF_TextureHandler *txh){ gf_sr_texture_update_frame(txh, 0); /*restart texture if needed (movie background controled by MediaControl)*/ if (txh->stream_finished && gf_mo_get_loop(txh->stream, 0)) gf_sr_texture_restart(txh);}static Bool back_gf_sr_texture_enabled(MFURL *url, GF_TextureHandler *txh){ Bool use_texture = back_use_texture(url); if (use_texture) { /*texture not ready*/ if (!txh->hwtx) { use_texture = 0; gf_sr_invalidate(txh->compositor, NULL); } tx_set_blend_mode(txh, tx_is_transparent(txh) ? TX_REPLACE : TX_DECAL); } return use_texture;}static void back_check_gf_sr_texture_change(GF_TextureHandler *txh, MFURL *url){ /*if open and changed, stop and play*/ if (txh->is_open) { if (! gf_sr_texture_check_url_change(txh, url)) return; gf_sr_texture_stop(txh); gf_sr_texture_play(txh, url); return; } /*if not open and changed play*/ if (url->count) gf_sr_texture_play(txh, url);}static void DestroyBackground2D(GF_Node *node){ Background2DStack *ptr; ptr = (Background2DStack *) gf_node_get_private(node); PreDestroyBindable(node, ptr->reg_stacks); gf_list_del(ptr->reg_stacks); gf_sr_texture_destroy(&ptr->txh); mesh_free(ptr->mesh); free(ptr);}static void RenderBackground2D(GF_Node *node, void *rs, Bool is_destroy){ M_Background2D *bck; Bool use_texture; Background2DStack *st; GF_Matrix mx; Bool is_layer; RenderEffect3D *eff = (RenderEffect3D *)rs; Render3D *sr; if (is_destroy) { DestroyBackground2D(node); return; } gf_node_dirty_clear(node, 0); bck = (M_Background2D *)node; st = (Background2DStack *) gf_node_get_private(node); sr = (Render3D*)st->compositor->visual_renderer->user_priv; assert(eff->backgrounds); /*first traverse, bound if needed*/ if (gf_list_find(eff->backgrounds, node) < 0) { gf_list_add(eff->backgrounds, node); assert(gf_list_find(st->reg_stacks, eff->backgrounds)==-1); gf_list_add(st->reg_stacks, eff->backgrounds); /*only bound if we're on top*/ if (gf_list_get(eff->backgrounds, 0) == bck) { if (!bck->isBound) Bindable_SetIsBound(node, 1); } /*open the stream if any*/ if (back_use_texture(&bck->url) && !st->txh.is_open) gf_sr_texture_play(&st->txh, &bck->url); /*in any case don't draw the first time (since the background could have been declared last)*/ gf_sr_invalidate(st->compositor, NULL); return; } if (!bck->isBound) return; if (eff->traversing_mode != TRAVERSE_RENDER_BINDABLE) return; use_texture = back_gf_sr_texture_enabled(&bck->url, &st->txh); /*no lights on background*/ VS3D_SetState(eff->surface, F3D_LIGHT | F3D_BLEND, 0); VS3D_PushMatrix(eff->surface); VS3D_SetMatrixMode(eff->surface, MAT_TEXTURE); VS3D_ResetMatrix(eff->surface); VS3D_SetMatrixMode(eff->surface, MAT_MODELVIEW); is_layer = (eff->surface->back_stack == eff->backgrounds) ? 0 : 1; /*little opt: if we clear the main surface clear it entirely */ if (!is_layer) { VS3D_ClearSurface(eff->surface, bck->backColor, FIX_ONE); if (!use_texture) { VS3D_PopMatrix(eff->surface); return; } /*we need a hack here because main vp is always rendered before main background, and in the case of a 2D viewport it modifies the modelview matrix, which we don't want ...*/ VS3D_ResetMatrix(eff->surface); } if (!use_texture || (!is_layer && st->txh.transparent) ) VS3D_SetMaterial2D(eff->surface, bck->backColor, FIX_ONE); if (use_texture) { VS3D_SetState(eff->surface, F3D_COLOR, !is_layer); eff->mesh_has_texture = tx_enable(&st->txh, NULL); } gf_mx_init(mx); if (eff->camera->is_3D) { Fixed sx, sy; /*reset matrix*/ VS3D_ResetMatrix(eff->surface); sx = sy = 2 * gf_mulfix(gf_tan(eff->camera->fieldOfView/2), eff->camera->z_far); if (eff->camera->width > eff->camera->height) { sx = gf_muldiv(sx, eff->camera->width, eff->camera->height); } else { sy = gf_muldiv(sy, eff->camera->height, eff->camera->width); } gf_mx_add_scale(&mx, sx, sy, FIX_ONE);#ifdef GPAC_FIXED_POINT gf_mx_add_translation(&mx, 0, 0, - (eff->camera->z_far/100)*99);#else gf_mx_add_translation(&mx, 0, 0, -0.999f*eff->camera->z_far);#endif } else { gf_mx_add_scale(&mx, eff->bbox.max_edge.x - eff->bbox.min_edge.x, eff->bbox.max_edge.y - eff->bbox.min_edge.y, FIX_ONE); /*when in layer2D, DON'T MOVE BACKGROUND TO ZFAR*/#ifdef GPAC_FIXED_POINT if (!is_layer) gf_mx_add_translation(&mx, 0, 0, -(eff->camera->z_far/100)*99);#else if (!is_layer) gf_mx_add_translation(&mx, 0, 0, -0.999f*eff->camera->z_far);#endif } VS3D_MultMatrix(eff->surface, mx.m); VS3D_DrawMesh(eff, st->mesh); if (eff->mesh_has_texture) { tx_disable(&st->txh); eff->mesh_has_texture = 0; } VS3D_PopMatrix(eff->surface);}static void b2D_set_bind(GF_Node *node){ Background2DStack *st = (Background2DStack *)gf_node_get_private(node); Bindable_OnSetBind(node, st->reg_stacks); /*and redraw scene*/ gf_sr_invalidate(st->compositor, NULL);}void R3D_InitBackground2D(Render3D *sr, GF_Node *node){ Background2DStack *ptr; GF_SAFEALLOC(ptr, Background2DStack); gf_sr_traversable_setup(ptr, node, sr->compositor); ptr->reg_stacks = gf_list_new(); ((M_Background2D *)node)->on_set_bind = b2D_set_bind; gf_sr_texture_setup(&ptr->txh, sr->compositor, node); ptr->txh.update_texture_fcnt = UpdateBackgroundTexture; gf_node_set_private(node, ptr); gf_node_set_callback_function(node, RenderBackground2D); ptr->mesh = new_mesh(); mesh_set_vertex(ptr->mesh, -PLANE_HSIZE, -PLANE_HSIZE, 0, 0, 0, FIX_ONE, 0, 0); mesh_set_vertex(ptr->mesh, PLANE_HSIZE, -PLANE_HSIZE, 0, 0, 0, FIX_ONE, FIX_ONE, 0); mesh_set_vertex(ptr->mesh, PLANE_HSIZE, PLANE_HSIZE, 0, 0, 0, FIX_ONE, FIX_ONE, FIX_ONE); mesh_set_vertex(ptr->mesh, -PLANE_HSIZE, PLANE_HSIZE, 0, 0, 0, FIX_ONE, 0, FIX_ONE); mesh_set_triangle(ptr->mesh, 0, 1, 2); mesh_set_triangle(ptr->mesh, 0, 2, 3); ptr->mesh->flags |= MESH_IS_2D;}void R3D_Background2DModified(GF_Node *node){ M_Background2D *bck = (M_Background2D *)node; Background2DStack *st = (Background2DStack *) gf_node_get_private(node); if (!st) return; back_check_gf_sr_texture_change(&st->txh, &bck->url); gf_sr_invalidate(st->txh.compositor, NULL);}static void DestroyBackground(GF_Node *node){ BackgroundStack *ptr = (BackgroundStack *) gf_node_get_private(node); PreDestroyBindable(node, ptr->reg_stacks); gf_list_del(ptr->reg_stacks); if (ptr->sky_mesh) mesh_free(ptr->sky_mesh); if (ptr->ground_mesh) mesh_free(ptr->ground_mesh); gf_sg_vrml_mf_reset(&ptr->ground_ang, GF_SG_VRML_MFFLOAT); gf_sg_vrml_mf_reset(&ptr->sky_ang, GF_SG_VRML_MFFLOAT); gf_sg_vrml_mf_reset(&ptr->ground_col, GF_SG_VRML_MFCOLOR); gf_sg_vrml_mf_reset(&ptr->sky_col, GF_SG_VRML_MFCOLOR); mesh_free(ptr->front_mesh); mesh_free(ptr->back_mesh); mesh_free(ptr->top_mesh); mesh_free(ptr->bottom_mesh); mesh_free(ptr->left_mesh); mesh_free(ptr->right_mesh); gf_sr_texture_destroy(&ptr->txh_front); gf_sr_texture_destroy(&ptr->txh_back); gf_sr_texture_destroy(&ptr->txh_top); gf_sr_texture_destroy(&ptr->txh_bottom); gf_sr_texture_destroy(&ptr->txh_left); gf_sr_texture_destroy(&ptr->txh_right); free(ptr);}#define COL_TO_RGBA(res, col) { res.red = col.red; res.green = col.green; res.blue = col.blue; res.alpha = FIX_ONE; }#define DOME_STEP_V 32#define DOME_STEP_H 16static void back_build_dome(GF_Mesh *mesh, MFFloat *angles, MFColor *color, Bool ground_dome){ u32 i, j, last_idx, ang_idx, new_idx; Bool pad; u32 step_div_h; GF_Vertex vx; SFColorRGBA start_col, end_col; Fixed start_angle, next_angle, angle, r, frac, first_angle; start_angle = 0; mesh_reset(mesh); start_col.red = start_col.green = start_col.blue = 0; end_col = start_col; if (color->count) { COL_TO_RGBA(start_col, color->vals[0]); end_col = start_col; if (color->count>1) COL_TO_RGBA(end_col, color->vals[1]); } start_col.alpha = end_col.alpha = FIX_ONE; vx.texcoords.x = vx.texcoords.y = 0; vx.color = start_col; vx.pos.x = vx.pos.z = 0; vx.pos.y = FIX_ONE; vx.normal.x = vx.normal.z = 0; vx.normal.y = -FIX_ONE; mesh_set_vertex_vx(mesh, &vx); last_idx = 0; ang_idx = 0; pad = 1; next_angle = first_angle = 0; if (angles->count) { next_angle = angles->vals[0]; first_angle = 7*next_angle/8; pad = 0; } step_div_h = DOME_STEP_H; i=0; if (ground_dome) { step_div_h *= 2; i=1; } for (; i<DOME_STEP_V; i++) { if (ground_dome) { angle = first_angle + (i * (GF_PI2-first_angle) / DOME_STEP_V); } else { angle = (i * GF_PI / DOME_STEP_V); } /*switch cols*/ if (angle >= next_angle) { if (ang_idx+1<=angles->count) { start_angle = next_angle; next_angle = angles->vals[ang_idx+1]; if (next_angle>GF_PI) next_angle=GF_PI; start_col = end_col; ang_idx++; if (ang_idx+1<color->count) { COL_TO_RGBA(end_col, color->vals[ang_idx+1]); } else { pad = 1; } } else { if (ground_dome) break; pad = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -