Ejemplo n.º 1
0
void map::castLight( int row, float start, float end, int xx, int xy, int yx, int yy,
                     const int offsetX, const int offsetY, const int offsetDistance )
{
    float newStart = 0.0f;
    float radius = 60.0f - offsetDistance;
    if( start < end ) {
        return;
    }
    bool blocked = false;
    for( int distance = row; distance <= radius && !blocked; distance++ ) {
        int deltaY = -distance;
        for( int deltaX = -distance; deltaX <= 0; deltaX++ ) {
            int currentX = offsetX + deltaX * xx + deltaY * xy;
            int currentY = offsetY + deltaX * yx + deltaY * yy;
            float leftSlope = (deltaX - 0.5f) / (deltaY + 0.5f);
            float rightSlope = (deltaX + 0.5f) / (deltaY - 0.5f);

            if( !(currentX >= 0 && currentY >= 0 && currentX < SEEX * my_MAPSIZE &&
                  currentY < SEEY * my_MAPSIZE) || start < rightSlope ) {
                continue;
            } else if( end > leftSlope ) {
                break;
            }

            //check if it's within the visible area and mark visible if so
            if( rl_dist(0, 0, deltaX, deltaY) <= radius ) {
                /*
                float bright = (float) (1 - (rStrat.radius(deltaX, deltaY) / radius));
                lightMap[currentX][currentY] = bright;
                */
                seen_cache[currentX][currentY] = true;
            }

            if( blocked ) {
                //previous cell was a blocking one
                if( light_transparency(currentX, currentY) == LIGHT_TRANSPARENCY_SOLID ) {
                    //hit a wall
                    newStart = rightSlope;
                    continue;
                } else {
                    blocked = false;
                    start = newStart;
                }
            } else {
                if( light_transparency(currentX, currentY) == LIGHT_TRANSPARENCY_SOLID &&
                    distance < radius ) {
                    //hit a wall within sight line
                    blocked = true;
                    castLight(distance + 1, start, leftSlope, xx, xy, yx, yy,
                              offsetX, offsetY, offsetDistance);
                    newStart = rightSlope;
                }
            }
        }
    }
}
Ejemplo n.º 2
0
void map::cache_seen(int fx, int fy, int tx, int ty, int max_range)
{
   if (!INBOUNDS(fx, fy) || !INBOUNDS(tx, ty)) return;

   const int ax = abs(tx - fx) << 1;
   const int ay = abs(ty - fy) << 1;
   const int dx = (fx < tx) ? 1 : -1;
   const int dy = (fy < ty) ? 1 : -1;
   int x = fx;
   int y = fy;
   int seen = true;

   // TODO: [lightmap] Pull out the common code here rather than duplication
   if (ax > ay)
   {
      int t = ay - (ax >> 1);
      do
      {
         if(t >= 0 && ((y + dy != ty) || (x + dx == tx)))
         {
            y += dy;
            t -= ax;
         }

         x += dx;
         t += ay;

         seen_cache[x][y] |= seen;
         if(light_transparency(x, y) == LIGHT_TRANSPARENCY_SOLID) seen = false;

      } while(!(x == tx && y == ty));
   }
Ejemplo n.º 3
0
void map::apply_light_ray(bool lit[LIGHTMAP_CACHE_X][LIGHTMAP_CACHE_Y],
                          int sx, int sy, int ex, int ey, float luminance, bool trig_brightcalc)
{
    int ax = abs(ex - sx) << 1;
    int ay = abs(ey - sy) << 1;
    int dx = (sx < ex) ? 1 : -1;
    int dy = (sy < ey) ? 1 : -1;
    int x = sx;
    int y = sy;

    if( sx == ex && sy == ey ) {
        return;
    }


    float transparency = LIGHT_TRANSPARENCY_CLEAR;
    float light = 0.0;
    int td = 0;
    // TODO: [lightmap] Pull out the common code here rather than duplication
    if (ax > ay) {
        int t = ay - (ax >> 1);
        do {
            if(t >= 0) {
                y += dy;
                t -= ax;
            }

            x += dx;
            t += ay;

            if (INBOUNDS(x, y)) {
                if (!lit[x][y]) {
                    // Multiple rays will pass through the same squares so we need to record that
                    lit[x][y] = true;

                    // We know x is the longest angle here and squares can ignore the abs calculation
                    light = 0.0;
                    if ( trig_brightcalc ) {
                        td = trig_dist(sx, sy, x, y);
                        light = luminance / ( td * td );
                    } else {
                        light = luminance / ((sx - x) * (sx - x));
                    }
                    lm[x][y] += light * transparency;
                }
                transparency *= light_transparency(x, y);
            }

            if (transparency <= LIGHT_TRANSPARENCY_SOLID) {
                break;
            }

        } while(!(x == ex && y == ey));
    } else {
Ejemplo n.º 4
0
bool map::trans( const tripoint &p ) const
{
    return light_transparency( p ) > LIGHT_TRANSPARENCY_SOLID;
}
Ejemplo n.º 5
0
bool map::trans(const int x, const int y) const
{
    return light_transparency(x, y) > LIGHT_TRANSPARENCY_SOLID;
}
Ejemplo n.º 6
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));

    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;
                }
            }
        }
    }
}
Ejemplo n.º 7
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 &current_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;
                }
            }
        }
    }
}
Ejemplo n.º 8
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;
            }
        }
    }
}