void map::add_light_from_items( const int x, const int y, const std::vector<item> &items ) { for( auto & itm : items ) { float ilum = 0.0; // brightness int iwidth = 0; // 0-360 degrees. 0 is a circular light_source int idir = 0; // otherwise, it's a light_arc pointed in this direction if( itm.getlight( ilum, iwidth, idir ) ) { if( iwidth > 0 ) { apply_light_arc( x, y, idir, ilum, iwidth ); } else { add_light_source( x, y, ilum ); } } } }
void map::add_light_from_items( const int x, const int y, std::list<item>::iterator begin, std::list<item>::iterator end ) { for( auto itm_it = begin; itm_it != end; ++itm_it ) { float ilum = 0.0; // brightness int iwidth = 0; // 0-360 degrees. 0 is a circular light_source int idir = 0; // otherwise, it's a light_arc pointed in this direction if( itm_it->getlight( ilum, iwidth, idir ) ) { if( iwidth > 0 ) { apply_light_arc( x, y, idir, ilum, iwidth ); } else { add_light_source( x, y, ilum ); } } } }
void map::generate_lightmap() { memset(lm, 0, sizeof(lm)); memset(sm, 0, sizeof(sm)); /* Bulk light sources wastefully cast rays into neighbors; a burning hospital can produce significant slowdown, so for stuff like fire and lava: * Step 1: Store the position and luminance in buffer via add_light_source, for efficient checking of neighbors. * Step 2: After everything else, iterate buffer and apply_light_source only in non-redundant directions * Step 3: Profit! */ memset(light_source_buffer, 0, sizeof(light_source_buffer)); constexpr int dir_x[] = { 0, -1 , 1, 0 }; // [0] constexpr int dir_y[] = { -1, 0 , 0, 1 }; // [1][X][2] constexpr int dir_d[] = { 180, 270, 0, 90 }; // [3] const bool u_is_inside = !is_outside(g->u.posx(), g->u.posy()); const float natural_light = g->natural_light_level(); const float hl = natural_light / 2; if (natural_light > LIGHT_SOURCE_BRIGHT) { // Apply sunlight, first light source so just assign for (int sx = DAYLIGHT_LEVEL - hl; sx < LIGHTMAP_CACHE_X - hl; ++sx) { for (int sy = DAYLIGHT_LEVEL - hl; sy < LIGHTMAP_CACHE_Y - hl; ++sy) { // In bright light indoor light exists to some degree if (!is_outside(sx, sy)) { lm[sx][sy] = LIGHT_AMBIENT_LOW; } else if (g->u.posx() == sx && g->u.posy() == sy ) { //Only apply daylight on square where player is standing to avoid flooding // the lightmap when in less than total sunlight. lm[sx][sy] = natural_light; } } } } apply_character_light( g->u ); for( auto &n : g->active_npc ) { apply_character_light( *n ); } // LIGHTMAP_CACHE_X = MAPSIZE * SEEX // LIGHTMAP_CACHE_Y = MAPSIZE * SEEY // Traverse the submaps in order for (int smx = 0; smx < my_MAPSIZE; ++smx) { for (int smy = 0; smy < my_MAPSIZE; ++smy) { auto const cur_submap = get_submap_at_grid( smx, smy ); for (int sx = 0; sx < SEEX; ++sx) { for (int sy = 0; sy < SEEY; ++sy) { const int x = sx + smx * SEEX; const int y = sy + smy * SEEY; // When underground natural_light is 0, if this changes we need to revisit // Only apply this whole thing if the player is inside, // buildings will be shadowed when outside looking in. if (natural_light > LIGHT_SOURCE_BRIGHT && u_is_inside && !is_outside(x, y)) { // Apply light sources for external/internal divide for(int i = 0; i < 4; ++i) { if (INBOUNDS(x + dir_x[i], y + dir_y[i]) && is_outside(x + dir_x[i], y + dir_y[i])) { lm[x][y] = natural_light; if (light_transparency(x, y) > LIGHT_TRANSPARENCY_SOLID) { apply_light_arc(x, y, dir_d[i], natural_light); } } } } if (cur_submap->lum[sx][sy]) { auto items = i_at(x, y); add_light_from_items(x, y, items.begin(), items.end()); } const ter_id terrain = cur_submap->ter[sx][sy]; if (terrain == t_lava) { add_light_source(x, y, 50 ); } else if (terrain == t_console) { add_light_source(x, y, 3 ); } else if (terrain == t_utility_light) { add_light_source(x, y, 35 ); } for( auto &fld : cur_submap->fld[sx][sy] ) { const field_entry *cur = &fld.second; // TODO: [lightmap] Attach light brightness to fields switch(cur->getFieldType()) { case fd_fire: if (3 == cur->getFieldDensity()) { add_light_source(x, y, 160); } else if (2 == cur->getFieldDensity()) { add_light_source(x, y, 60); } else { add_light_source(x, y, 16); } break; case fd_fire_vent: case fd_flame_burst: add_light_source(x, y, 8); break; case fd_electricity: case fd_plasma: if (3 == cur->getFieldDensity()) { add_light_source(x, y, 8); } else if (2 == cur->getFieldDensity()) { add_light_source(x, y, 1); } else { apply_light_source(x, y, LIGHT_SOURCE_LOCAL, trigdist); // kinda a hack as the square will still get marked } break; case fd_incendiary: if (3 == cur->getFieldDensity()) { add_light_source(x, y, 30); } else if (2 == cur->getFieldDensity()) { add_light_source(x, y, 16); } else { add_light_source(x, y, 8); } break; case fd_laser: apply_light_source(x, y, 1, trigdist); break; case fd_spotlight: add_light_source(x, y, 20); break; case fd_dazzling: add_light_source(x, y, 2); break; default: //Suppress warnings break; } } } } } } for (size_t i = 0; i < g->num_zombies(); ++i) { auto &critter = g->zombie(i); if(critter.is_hallucination()) { continue; } int mx = critter.posx(); int my = critter.posy(); if (INBOUNDS(mx, my)) { if (critter.has_effect("onfire")) { apply_light_source(mx, my, 3, trigdist); } // TODO: [lightmap] Attach natural light brightness to creatures // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot) // TODO: [lightmap] Allow creatures to have facing and arc lights if (critter.type->luminance > 0) { apply_light_source(mx, my, critter.type->luminance, trigdist); } } } // Apply any vehicle light sources VehicleList vehs = get_vehicles(); for( auto &vv : vehs ) { vehicle *v = vv.v; if(v->lights_on) { int dir = v->face.dir(); float veh_luminance = 0.0; float iteration = 1.0; std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_CONE_LIGHT); for( auto &light_indice : light_indices ) { veh_luminance += ( v->part_info( light_indice ).bonus / iteration ); iteration = iteration * 1.1; } if (veh_luminance > LL_LIT) { for( auto &light_indice : light_indices ) { int px = vv.x + v->parts[light_indice].precalc[0].x; int py = vv.y + v->parts[light_indice].precalc[0].y; if(INBOUNDS(px, py)) { add_light_source(px, py, SQRT_2); // Add a little surrounding light apply_light_arc( px, py, dir + v->parts[light_indice].direction, veh_luminance, 45 ); } } } } if(v->overhead_lights_on) { std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_CIRCLE_LIGHT); for( auto &light_indice : light_indices ) { if( ( calendar::turn % 2 && v->part_info( light_indice ).has_flag( VPFLAG_ODDTURN ) ) || ( !( calendar::turn % 2 ) && v->part_info( light_indice ).has_flag( VPFLAG_EVENTURN ) ) || ( !v->part_info( light_indice ).has_flag( VPFLAG_EVENTURN ) && !v->part_info( light_indice ).has_flag( VPFLAG_ODDTURN ) ) ) { int px = vv.x + v->parts[light_indice].precalc[0].x; int py = vv.y + v->parts[light_indice].precalc[0].y; if(INBOUNDS(px, py)) { add_light_source( px, py, v->part_info( light_indice ).bonus ); } } } } // why reinvent the [lightmap] wheel if(v->dome_lights_on) { std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_DOME_LIGHT); for( auto &light_indice : light_indices ) { int px = vv.x + v->parts[light_indice].precalc[0].x; int py = vv.y + v->parts[light_indice].precalc[0].y; if(INBOUNDS(px, py)) { add_light_source( px, py, v->part_info( light_indice ).bonus ); } } } if(v->aisle_lights_on) { std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_AISLE_LIGHT); for( auto &light_indice : light_indices ) { int px = vv.x + v->parts[light_indice].precalc[0].x; int py = vv.y + v->parts[light_indice].precalc[0].y; if(INBOUNDS(px, py)) { add_light_source( px, py, v->part_info( light_indice ).bonus ); } } } if(v->has_atomic_lights) { // atomic light is always on std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_ATOMIC_LIGHT); for( auto &light_indice : light_indices ) { int px = vv.x + v->parts[light_indice].precalc[0].x; int py = vv.y + v->parts[light_indice].precalc[0].y; if(INBOUNDS(px, py)) { add_light_source( px, py, v->part_info( light_indice ).bonus ); } } } for( size_t p = 0; p < v->parts.size(); ++p ) { int px = vv.x + v->parts[p].precalc[0].x; int py = vv.y + v->parts[p].precalc[0].y; if( !INBOUNDS( px, py ) ) { continue; } if( v->part_flag( p, VPFLAG_CARGO ) && !v->part_flag( p, "COVERED" ) ) { add_light_from_items( px, py, v->get_items(p).begin(), v->get_items(p).end() ); } } } /* Now that we have position and intensity of all bulk light sources, apply_ them This may seem like extra work, but take a 12x12 raging inferno: unbuffered: (12^2)*(160*4) = apply_light_ray x 92160 buffered: (12*4)*(160) = apply_light_ray x 7680 */ for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) { for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) { if ( light_source_buffer[sx][sy] > 0. ) { apply_light_source(sx, sy, light_source_buffer[sx][sy], ( trigdist && light_source_buffer[sx][sy] > 3. ) ); } } } if (g->u.has_active_bionic("bio_night") ) { for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) { for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) { if (rl_dist(sx, sy, g->u.posx(), g->u.posy()) < 15) { lm[sx][sy] = 0; } } } } }
void map::generate_lightmap() { memset(lm, 0, sizeof(lm)); memset(sm, 0, sizeof(sm)); /* Bulk light sources wastefully cast rays into neighbors; a burning hospital can produce significant slowdown, so for stuff like fire and lava: * Step 1: Store the position and luminance in buffer via add_light_source, for efficient checking of neighbors. * Step 2: After everything else, iterate buffer and apply_light_source only in non-redundant directions * Step 3: Profit! */ memset(light_source_buffer, 0, sizeof(light_source_buffer)); const int dir_x[] = { 1, 0 , -1, 0 }; const int dir_y[] = { 0, 1 , 0, -1 }; const int dir_d[] = { 180, 270, 0, 90 }; const float held_luminance = g->u.active_light(); const float natural_light = g->natural_light_level(); if (natural_light > LIGHT_SOURCE_BRIGHT) { // Apply sunlight, first light source so just assign for(int sx = DAYLIGHT_LEVEL - (natural_light / 2); sx < LIGHTMAP_CACHE_X - (natural_light / 2); ++sx) { for(int sy = DAYLIGHT_LEVEL - (natural_light / 2); sy < LIGHTMAP_CACHE_Y - (natural_light / 2); ++sy) { // In bright light indoor light exists to some degree if (!is_outside(sx, sy)) { lm[sx][sy] = LIGHT_AMBIENT_LOW; } else if (g->u.posx == sx && g->u.posy == sy ) { //Only apply daylight on square where player is standing to avoid flooding // the lightmap when in less than total sunlight. lm[sx][sy] = natural_light; } } } } // Apply player light sources if (held_luminance > LIGHT_AMBIENT_LOW) { apply_light_source(g->u.posx, g->u.posy, held_luminance, trigdist); } for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) { for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) { const ter_id terrain = ter(sx, sy); const std::vector<item> &items = i_at(sx, sy); field ¤t_field = field_at(sx, sy); // When underground natural_light is 0, if this changes we need to revisit // Only apply this whole thing if the player is inside, // buildings will be shadowed when outside looking in. if (natural_light > LIGHT_AMBIENT_LOW && !is_outside(g->u.posx, g->u.posy) ) { if (!is_outside(sx, sy)) { // Apply light sources for external/internal divide for(int i = 0; i < 4; ++i) { if (INBOUNDS(sx + dir_x[i], sy + dir_y[i]) && is_outside(sx + dir_x[i], sy + dir_y[i])) { lm[sx][sy] = natural_light; if (light_transparency(sx, sy) > LIGHT_TRANSPARENCY_SOLID) { apply_light_arc(sx, sy, dir_d[i], natural_light); } } } } } for( std::vector<item>::const_iterator itm = items.begin(); itm != items.end(); ++itm ) { float ilum = 0.0; // brightness int iwidth = 0; // 0-360 degrees. 0 is a circular light_source int idir = 0; // otherwise, it's a light_arc pointed in this direction if ( itm->getlight(ilum, iwidth, idir ) ) { if ( iwidth > 0 ) { apply_light_arc( sx, sy, idir, ilum, iwidth ); } else { add_light_source(sx, sy, ilum); } } } if(terrain == t_lava) { add_light_source(sx, sy, 50 ); } if(terrain == t_console) { add_light_source(sx, sy, 3 ); } if(terrain == t_emergency_light) { add_light_source(sx, sy, 3 ); } if(terrain == t_utility_light) { add_light_source(sx, sy, 35 ); } field_entry *cur = NULL; for(std::map<field_id, field_entry *>::iterator field_list_it = current_field.getFieldStart(); field_list_it != current_field.getFieldEnd(); ++field_list_it) { cur = field_list_it->second; if(cur == NULL) { continue; } // TODO: [lightmap] Attach light brightness to fields switch(cur->getFieldType()) { case fd_fire: if (3 == cur->getFieldDensity()) { add_light_source(sx, sy, 160); } else if (2 == cur->getFieldDensity()) { add_light_source(sx, sy, 60); } else { add_light_source(sx, sy, 16); } break; case fd_fire_vent: case fd_flame_burst: add_light_source(sx, sy, 8); break; case fd_electricity: case fd_plasma: if (3 == cur->getFieldDensity()) { add_light_source(sx, sy, 8); } else if (2 == cur->getFieldDensity()) { add_light_source(sx, sy, 1); } else { apply_light_source(sx, sy, LIGHT_SOURCE_LOCAL, trigdist); // kinda a hack as the square will still get marked } break; case fd_incendiary: if (3 == cur->getFieldDensity()) { add_light_source(sx, sy, 30); } else if (2 == cur->getFieldDensity()) { add_light_source(sx, sy, 16); } else { add_light_source(sx, sy, 8); } break; case fd_laser: apply_light_source(sx, sy, 1, trigdist); break; case fd_spotlight: add_light_source(sx, sy, 20); break; case fd_dazzling: add_light_source(sx, sy, 2); break; default: //Suppress warnings break; } } } } for (size_t i = 0; i < g->num_zombies(); ++i) { int mx = g->zombie(i).posx(); int my = g->zombie(i).posy(); if (INBOUNDS(mx, my)) { if (g->zombie(i).has_effect("onfire")) { apply_light_source(mx, my, 3, trigdist); } // TODO: [lightmap] Attach natural light brightness to creatures // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot) // TODO: [lightmap] Allow creatures to have facing and arc lights if (g->zombie(i).type->luminance > 0) { apply_light_source(mx, my, g->zombie(i).type->luminance, trigdist); } } } // Apply any vehicle light sources VehicleList vehs = get_vehicles(); for( size_t v = 0; v < vehs.size(); ++v ) { if(vehs[v].v->lights_on) { int dir = vehs[v].v->face.dir(); float veh_luminance = 0.0; float iteration = 1.0; std::vector<int> light_indices = vehs[v].v->all_parts_with_feature(VPFLAG_CONE_LIGHT); for (std::vector<int>::iterator part = light_indices.begin(); part != light_indices.end(); ++part) { veh_luminance += ( vehs[v].v->part_info(*part).bonus / iteration ); iteration = iteration * 1.1; } if (veh_luminance > LL_LIT) { for (std::vector<int>::iterator part = light_indices.begin(); part != light_indices.end(); ++part) { int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0]; int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0]; if(INBOUNDS(px, py)) { apply_light_arc(px, py, dir + vehs[v].v->parts[*part].direction, veh_luminance, 45); } } } } if(vehs[v].v->overhead_lights_on) { std::vector<int> light_indices = vehs[v].v->all_parts_with_feature(VPFLAG_CIRCLE_LIGHT); for (std::vector<int>::iterator part = light_indices.begin(); part != light_indices.end(); ++part) { if((calendar::turn % 2 && vehs[v].v->part_info(*part).has_flag(VPFLAG_ODDTURN)) || (!(calendar::turn % 2) && vehs[v].v->part_info(*part).has_flag(VPFLAG_EVENTURN)) || (!vehs[v].v->part_info(*part).has_flag(VPFLAG_EVENTURN) && !vehs[v].v->part_info(*part).has_flag(VPFLAG_ODDTURN))) { int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0]; int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0]; if(INBOUNDS(px, py)) { add_light_source( px, py, vehs[v].v->part_info(*part).bonus ); } } } } } /* Now that we have position and intensity of all bulk light sources, apply_ them This may seem like extra work, but take a 12x12 raging inferno: unbuffered: (12^2)*(160*4) = apply_light_ray x 92160 buffered: (12*4)*(160) = apply_light_ray x 7680 */ for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) { for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) { if ( light_source_buffer[sx][sy] > 0. ) { apply_light_source(sx, sy, light_source_buffer[sx][sy], ( trigdist && light_source_buffer[sx][sy] > 3. ) ); } } } if (g->u.has_active_bionic("bio_night") ) { for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) { for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) { if (rl_dist(sx, sy, g->u.posx, g->u.posy) < 15) { lm[sx][sy] = 0; } } } } }
void map::generate_lightmap( const int zlev ) { auto &map_cache = get_cache( zlev ); auto &lm = map_cache.lm; auto &sm = map_cache.sm; auto &outside_cache = map_cache.outside_cache; std::memset(lm, 0, sizeof(lm)); std::memset(sm, 0, sizeof(sm)); /* Bulk light sources wastefully cast rays into neighbors; a burning hospital can produce significant slowdown, so for stuff like fire and lava: * Step 1: Store the position and luminance in buffer via add_light_source, for efficient checking of neighbors. * Step 2: After everything else, iterate buffer and apply_light_source only in non-redundant directions * Step 3: ???? * Step 4: Profit! */ auto &light_source_buffer = map_cache.light_source_buffer; std::memset(light_source_buffer, 0, sizeof(light_source_buffer)); constexpr int dir_x[] = { 0, -1 , 1, 0 }; // [0] constexpr int dir_y[] = { -1, 0 , 0, 1 }; // [1][X][2] constexpr int dir_d[] = { 90, 0, 180, 270 }; // [3] const float natural_light = g->natural_light_level( zlev ); const float inside_light = (natural_light > LIGHT_SOURCE_BRIGHT) ? LIGHT_AMBIENT_LOW + 1.0 : LIGHT_AMBIENT_MINIMAL; // Apply sunlight, first light source so just assign for( int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx ) { for( int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy ) { // In bright light indoor light exists to some degree if( !outside_cache[sx][sy] ) { lm[sx][sy] = inside_light; } else { lm[sx][sy] = natural_light; } } } apply_character_light( g->u ); for( auto &n : g->active_npc ) { apply_character_light( *n ); } // Traverse the submaps in order for (int smx = 0; smx < my_MAPSIZE; ++smx) { for (int smy = 0; smy < my_MAPSIZE; ++smy) { auto const cur_submap = get_submap_at_grid( smx, smy, zlev ); for (int sx = 0; sx < SEEX; ++sx) { for (int sy = 0; sy < SEEY; ++sy) { const int x = sx + smx * SEEX; const int y = sy + smy * SEEY; const tripoint p( x, y, zlev ); // Project light into any openings into buildings. if (natural_light > LIGHT_SOURCE_BRIGHT && !outside_cache[p.x][p.y]) { // Apply light sources for external/internal divide for(int i = 0; i < 4; ++i) { if (INBOUNDS(p.x + dir_x[i], p.y + dir_y[i]) && outside_cache[p.x + dir_x[i]][p.y + dir_y[i]]) { lm[p.x][p.y] = natural_light; if (light_transparency( p ) > LIGHT_TRANSPARENCY_SOLID) { apply_directional_light( p, dir_d[i], natural_light ); } } } } if( cur_submap->lum[sx][sy] && has_items( p ) ) { auto items = i_at( p ); add_light_from_items( p, items.begin(), items.end() ); } const ter_id terrain = cur_submap->ter[sx][sy]; if (terrain == t_lava) { add_light_source( p, 50 ); } else if (terrain == t_console) { add_light_source( p, 10 ); } else if (terrain == t_utility_light) { add_light_source( p, 240 ); } for( auto &fld : cur_submap->fld[sx][sy] ) { const field_entry *cur = &fld.second; // TODO: [lightmap] Attach light brightness to fields switch(cur->getFieldType()) { case fd_fire: if (3 == cur->getFieldDensity()) { add_light_source( p, 160 ); } else if (2 == cur->getFieldDensity()) { add_light_source( p, 60 ); } else { add_light_source( p, 20 ); } break; case fd_fire_vent: case fd_flame_burst: add_light_source( p, 20 ); break; case fd_electricity: case fd_plasma: if (3 == cur->getFieldDensity()) { add_light_source( p, 20 ); } else if (2 == cur->getFieldDensity()) { add_light_source( p, 4 ); } else { // Kinda a hack as the square will still get marked. apply_light_source( p, LIGHT_SOURCE_LOCAL ); } break; case fd_incendiary: if (3 == cur->getFieldDensity()) { add_light_source( p, 160 ); } else if (2 == cur->getFieldDensity()) { add_light_source( p, 60 ); } else { add_light_source( p, 20 ); } break; case fd_laser: apply_light_source( p, 4 ); break; case fd_spotlight: add_light_source( p, 80 ); break; case fd_dazzling: add_light_source( p, 5 ); break; default: //Suppress warnings break; } } } } } } for (size_t i = 0; i < g->num_zombies(); ++i) { auto &critter = g->zombie(i); if(critter.is_hallucination()) { continue; } const tripoint &mp = critter.pos(); if( inbounds( mp ) ) { if (critter.has_effect( effect_onfire)) { apply_light_source( mp, 8 ); } // TODO: [lightmap] Attach natural light brightness to creatures // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot) // TODO: [lightmap] Allow creatures to have facing and arc lights if (critter.type->luminance > 0) { apply_light_source( mp, critter.type->luminance ); } } } // Apply any vehicle light sources VehicleList vehs = get_vehicles(); for( auto &vv : vehs ) { vehicle *v = vv.v; if(v->lights_on) { int dir = v->face.dir(); float veh_luminance = 0.0; float iteration = 1.0; std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_CONE_LIGHT); for( auto &light_indice : light_indices ) { veh_luminance += ( v->part_info( light_indice ).bonus / iteration ); iteration = iteration * 1.1; } if (veh_luminance > LL_LIT) { for( auto &light_indice : light_indices ) { tripoint pp = tripoint( vv.x, vv.y, vv.z ) + v->parts[light_indice].precalc[0]; if( inbounds( pp ) ) { add_light_source( pp, SQRT_2 ); // Add a little surrounding light apply_light_arc( pp, dir + v->parts[light_indice].direction, veh_luminance, 45 ); } } } } if(v->overhead_lights_on) { std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_CIRCLE_LIGHT); for( auto &light_indice : light_indices ) { if( ( calendar::turn % 2 && v->part_info( light_indice ).has_flag( VPFLAG_ODDTURN ) ) || ( !( calendar::turn % 2 ) && v->part_info( light_indice ).has_flag( VPFLAG_EVENTURN ) ) || ( !v->part_info( light_indice ).has_flag( VPFLAG_EVENTURN ) && !v->part_info( light_indice ).has_flag( VPFLAG_ODDTURN ) ) ) { tripoint pp = tripoint( vv.x, vv.y, vv.z ) + v->parts[light_indice].precalc[0]; if(inbounds( pp )) { add_light_source( pp, v->part_info( light_indice ).bonus ); } } } } // why reinvent the [lightmap] wheel if(v->dome_lights_on) { std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_DOME_LIGHT); for( auto &light_indice : light_indices ) { tripoint pp = tripoint( vv.x, vv.y, vv.z ) + v->parts[light_indice].precalc[0]; if( inbounds( pp )) { add_light_source( pp, v->part_info( light_indice ).bonus ); } } } if(v->aisle_lights_on) { std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_AISLE_LIGHT); for( auto &light_indice : light_indices ) { tripoint pp = tripoint( vv.x, vv.y, vv.z ) + v->parts[light_indice].precalc[0]; if( inbounds( pp )) { add_light_source( pp, v->part_info( light_indice ).bonus ); } } } if(v->has_atomic_lights) { // atomic light is always on std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_ATOMIC_LIGHT); for( auto &light_indice : light_indices ) { tripoint pp = tripoint( vv.x, vv.y, vv.z ) + v->parts[light_indice].precalc[0]; if(inbounds( pp )) { add_light_source( pp, v->part_info( light_indice ).bonus ); } } } for( size_t p = 0; p < v->parts.size(); ++p ) { tripoint pp = tripoint( vv.x, vv.y, vv.z ) + v->parts[p].precalc[0]; if( !inbounds( pp ) ) { continue; } if( v->part_flag( p, VPFLAG_CARGO ) && !v->part_flag( p, "COVERED" ) ) { add_light_from_items( pp, v->get_items(p).begin(), v->get_items(p).end() ); } } } /* Now that we have position and intensity of all bulk light sources, apply_ them This may seem like extra work, but take a 12x12 raging inferno: unbuffered: (12^2)*(160*4) = apply_light_ray x 92160 buffered: (12*4)*(160) = apply_light_ray x 7680 */ const tripoint cache_start( 0, 0, zlev ); const tripoint cache_end( LIGHTMAP_CACHE_X, LIGHTMAP_CACHE_Y, zlev ); for( const tripoint &p : points_in_rectangle( cache_start, cache_end ) ) { if( light_source_buffer[p.x][p.y] > 0.0 ) { apply_light_source( p, light_source_buffer[p.x][p.y] ); } } if (g->u.has_active_bionic("bio_night") ) { for( const tripoint &p : points_in_rectangle( cache_start, cache_end ) ) { if( rl_dist( p, g->u.pos() ) < 15 ) { lm[p.x][p.y] = LIGHT_AMBIENT_MINIMAL; } } } }
int main(void) { // Allocating scene Scene * scene = new_scene(MAX_OBJECTS_NUMBER, MAX_LIGHT_SOURCES_NUMBER, BACKGROUND_COLOR); // Allocating new sphere Float radius = 100; Point3d center = point3d(0, 0, 0); Color sphere_color = rgb(250, 30, 30); Material sphere_material = material(1, 5, 5, 10, 0, 10); Object3d * sphere = new_sphere(center, radius, sphere_color, sphere_material); // Adding sphere to the scene add_object(scene, sphere); // Allocating new triangle Object3d * triangle = new_triangle(point3d(-700, -700, -130), // vertex 1 point3d( 700, -700, -130), // vertex 2 point3d( 0, 400, -130), // vertex 3 rgb(100, 255, 30), // color material(1, 6, 0, 2, 0, 0) // surface params ); // Adding triangle to the scene add_object(scene, triangle); // Loading 3D model of cow from *.obj file // defining transformations and parameters of 3D model // TODO: must be refactored... SceneFaceHandlerParams load_params = new_scene_face_handler_params(scene, // scale: 40, // move dx, dy, dz: -150, -100, 30, // rotate around axises x, y, z: 0, 0, 0, // color rgb(200, 200, 50), // surface params material(2, 3, 0, 0, 0, 0) ); load_obj("./demo/models/cow.obj", // default handler which adding polygons of 3D model to scene: scene_face_handler, &load_params); // This function is requried (bulding k-d tree of entire scene) prepare_scene(scene); printf("\nNumber of polygons: %i\n", scene->last_object_index + 1); // Allocating new light source Color light_source_color = rgb(255, 255, 255); Point3d light_source_location = point3d(-300, 300, 300); LightSource3d * light_source = new_light_source(light_source_location, light_source_color); // Adding light source to the scene add_light_source(scene, light_source); // Adding fog Float density = 0.002; set_exponential_fog(scene, density); // Allocating camera // TODO: It's a pity, but quaternions are not implemented yet :( Point3d camera_location = point3d(0, 500, 0); Float focus = 320; Float x_angle = -1.57; Float y_angle = 0; Float z_angle = 3.14; Camera * camera = new_camera(camera_location, x_angle, y_angle, z_angle, focus); // Rotate camera if needed // rotate_camera(camera, d_x_angle, d_y_angle, d_z_angle); // Move camera if needed // move_camera(camera, vector3df(d_x, d_y, d_z)); // Alocate new canvas, to render scene on it Canvas * canvas = new_canvas(CANVAS_W, CANVAS_H); render_scene(scene, camera, canvas, THREADS_NUM); // Saving rendered image in PNG format write_png("example.png", canvas); release_canvas(canvas); release_scene(scene); release_camera(camera); return 0; }