Annotation of doom/r_plane.c, revision 1.1.1.2

1.1       root        1: 
1.1.1.2 ! root        2: //**************************************************************************
        !             3: //**
        !             4: //** r_plane.c : Heretic 2 : Raven Software, Corp.
        !             5: //**
        !             6: //** $RCSfile: r_plane.c,v $
        !             7: //** $Revision: 1.5 $
        !             8: //** $Date: 95/07/13 15:17:12 $
        !             9: //** $Author: cjr $
        !            10: //**
        !            11: //**************************************************************************
1.1       root       12: 
1.1.1.2 ! root       13: // HEADER FILES ------------------------------------------------------------
1.1       root       14: 
1.1.1.2 ! root       15: #include "h2def.h"
        !            16: #include "r_local.h"
1.1       root       17: 
1.1.1.2 ! root       18: // MACROS ------------------------------------------------------------------
1.1       root       19: 
1.1.1.2 ! root       20: // TYPES -------------------------------------------------------------------
1.1       root       21: 
1.1.1.2 ! root       22: // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
1.1       root       23: 
1.1.1.2 ! root       24: // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
        !            25: 
        !            26: // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
        !            27: 
        !            28: // EXTERNAL DATA DECLARATIONS ----------------------------------------------
        !            29: 
        !            30: extern fixed_t Sky1ScrollDelta;
        !            31: extern fixed_t Sky2ScrollDelta;
        !            32: 
        !            33: // PUBLIC DATA DEFINITIONS -------------------------------------------------
        !            34: 
        !            35: int Sky1Texture;
        !            36: int Sky2Texture;
        !            37: fixed_t Sky1ColumnOffset;
        !            38: fixed_t Sky2ColumnOffset;
        !            39: int skyflatnum;
        !            40: int skytexturemid;
        !            41: fixed_t skyiscale;
        !            42: boolean DoubleSky;
        !            43: planefunction_t floorfunc, ceilingfunc;
        !            44: 
        !            45: // Opening
        !            46: visplane_t visplanes[MAXVISPLANES], *lastvisplane;
        !            47: visplane_t *floorplane, *ceilingplane;
        !            48: short openings[MAXOPENINGS], *lastopening;
        !            49: 
        !            50: // Clip values are the solid pixel bounding the range.
        !            51: // floorclip start out SCREENHEIGHT
1.1       root       52: // ceilingclip starts out -1
1.1.1.2 ! root       53: short floorclip[SCREENWIDTH];
        !            54: short ceilingclip[SCREENWIDTH];
1.1       root       55: 
1.1.1.2 ! root       56: // spanstart holds the start of a plane span, initialized to 0
        !            57: int spanstart[SCREENHEIGHT];
        !            58: int spanstop[SCREENHEIGHT];
1.1       root       59: 
1.1.1.2 ! root       60: // Texture mapping
        !            61: lighttable_t **planezlight;
        !            62: fixed_t planeheight;
        !            63: fixed_t yslope[SCREENHEIGHT];
        !            64: fixed_t distscale[SCREENWIDTH];
        !            65: fixed_t basexscale, baseyscale;
        !            66: fixed_t cachedheight[SCREENHEIGHT];
        !            67: fixed_t cacheddistance[SCREENHEIGHT];
        !            68: fixed_t cachedxstep[SCREENHEIGHT];
        !            69: fixed_t cachedystep[SCREENHEIGHT];
        !            70: 
        !            71: // PRIVATE DATA DEFINITIONS ------------------------------------------------
1.1       root       72: 
1.1.1.2 ! root       73: // CODE --------------------------------------------------------------------
1.1       root       74: 
1.1.1.2 ! root       75: //==========================================================================
        !            76: //
        !            77: // R_InitSky
        !            78: //
        !            79: // Called at level load.
        !            80: //
        !            81: //==========================================================================
1.1       root       82: 
1.1.1.2 ! root       83: void R_InitSky(int map)
        !            84: {
        !            85:        Sky1Texture = P_GetMapSky1Texture(map);
        !            86:        Sky2Texture = P_GetMapSky2Texture(map);
        !            87:        Sky1ScrollDelta = P_GetMapSky1ScrollDelta(map);
        !            88:        Sky2ScrollDelta = P_GetMapSky2ScrollDelta(map);
        !            89:        Sky1ColumnOffset = 0;
        !            90:        Sky2ColumnOffset = 0;
        !            91:        DoubleSky = P_GetMapDoubleSky(map);
        !            92: }
1.1       root       93: 
1.1.1.2 ! root       94: //==========================================================================
        !            95: //
        !            96: // R_InitSkyMap
        !            97: //
        !            98: // Called whenever the view size changes.
        !            99: //
        !           100: //==========================================================================
1.1       root      101: 
1.1.1.2 ! root      102: void R_InitSkyMap(void)
1.1       root      103: {
1.1.1.2 ! root      104:        skyflatnum = R_FlatNumForName("F_SKY");
1.1       root      105:        skytexturemid = 200*FRACUNIT;
                    106:        skyiscale = FRACUNIT;
                    107: }
                    108: 
1.1.1.2 ! root      109: //==========================================================================
        !           110: //
        !           111: // R_InitPlanes
        !           112: //
        !           113: // Called at game startup.
        !           114: //
        !           115: //==========================================================================
1.1       root      116: 
1.1.1.2 ! root      117: void R_InitPlanes(void)
1.1       root      118: {
                    119: }
                    120: 
1.1.1.2 ! root      121: //==========================================================================
        !           122: //
        !           123: // R_MapPlane
        !           124: //
        !           125: // Globals used: planeheight, ds_source, basexscale, baseyscale,
        !           126: // viewx, viewy.
        !           127: //
        !           128: //==========================================================================
1.1       root      129: 
1.1.1.2 ! root      130: void R_MapPlane(int y, int x1, int x2)
1.1       root      131: {
1.1.1.2 ! root      132:        angle_t angle;
        !           133:        fixed_t distance, length;
        !           134:        unsigned index;
        !           135: 
1.1       root      136: #ifdef RANGECHECK
1.1.1.2 ! root      137:        if(x2 < x1 || x1 < 0 || x2 >= viewwidth || (unsigned)y > viewheight)
        !           138:        {
        !           139:                I_Error("R_MapPlane: %i, %i at %i", x1, x2, y);
        !           140:        }
1.1       root      141: #endif
                    142: 
1.1.1.2 ! root      143:        if(planeheight != cachedheight[y])
1.1       root      144:        {
                    145:                cachedheight[y] = planeheight;
1.1.1.2 ! root      146:                distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]);
        !           147:                ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale);
        !           148:                ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale);
1.1       root      149:        }
                    150:        else
                    151:        {
                    152:                distance = cacheddistance[y];
                    153:                ds_xstep = cachedxstep[y];
                    154:                ds_ystep = cachedystep[y];
                    155:        }
                    156:        
1.1.1.2 ! root      157:        length = FixedMul(distance, distscale[x1]);
        !           158:        angle = (viewangle+xtoviewangle[x1])>>ANGLETOFINESHIFT;
        !           159:        ds_xfrac = viewx+FixedMul(finecosine[angle], length);
        !           160:        ds_yfrac = -viewy-FixedMul(finesine[angle], length);
1.1       root      161: 
1.1.1.2 ! root      162:        if(fixedcolormap)
        !           163:        {
1.1       root      164:                ds_colormap = fixedcolormap;
1.1.1.2 ! root      165:        }
1.1       root      166:        else
                    167:        {
                    168:                index = distance >> LIGHTZSHIFT;
1.1.1.2 ! root      169:                if(index >= MAXLIGHTZ )
        !           170:                {
1.1       root      171:                        index = MAXLIGHTZ-1;
1.1.1.2 ! root      172:                }
1.1       root      173:                ds_colormap = planezlight[index];
                    174:        }
1.1.1.2 ! root      175: 
1.1       root      176:        ds_y = y;
                    177:        ds_x1 = x1;
                    178:        ds_x2 = x2;
                    179: 
1.1.1.2 ! root      180:        spanfunc(); // High or low detail
        !           181: }
1.1       root      182: 
1.1.1.2 ! root      183: //==========================================================================
        !           184: //
        !           185: // R_ClearPlanes
        !           186: //
        !           187: // Called at the beginning of each frame.
        !           188: //
        !           189: //==========================================================================
1.1       root      190: 
1.1.1.2 ! root      191: void R_ClearPlanes(void)
1.1       root      192: {
1.1.1.2 ! root      193:        int i;
        !           194:        angle_t angle;
        !           195: 
        !           196:        // Opening / clipping determination
        !           197:        for(i = 0; i < viewwidth; i++)
1.1       root      198:        {
                    199:                floorclip[i] = viewheight;
                    200:                ceilingclip[i] = -1;
                    201:        }
                    202: 
                    203:        lastvisplane = visplanes;
                    204:        lastopening = openings;
                    205: 
1.1.1.2 ! root      206:        // Texture calculation
        !           207:        memset(cachedheight, 0, sizeof(cachedheight));  
        !           208:        angle = (viewangle-ANG90)>>ANGLETOFINESHIFT; // left to right mapping
        !           209:        // Scale will be unit scale at SCREENWIDTH/2 distance
        !           210:        basexscale = FixedDiv(finecosine[angle], centerxfrac);
        !           211:        baseyscale = -FixedDiv(finesine[angle], centerxfrac);
        !           212: }
1.1       root      213: 
1.1.1.2 ! root      214: //==========================================================================
        !           215: //
        !           216: // R_FindPlane
        !           217: //
        !           218: //==========================================================================
1.1       root      219: 
                    220: visplane_t *R_FindPlane(fixed_t height, int picnum,
                    221:        int lightlevel, int special)
                    222: {
                    223:        visplane_t *check;
                    224: 
1.1.1.2 ! root      225:        if(special < 150)
        !           226:        { // Don't let low specials affect search
        !           227:                special = 0;
        !           228:        }
        !           229: 
1.1       root      230:        if(picnum == skyflatnum)
1.1.1.2 ! root      231:        { // All skies map together
1.1       root      232:                height = 0;
                    233:                lightlevel = 0;
                    234:        }
                    235: 
                    236:        for(check = visplanes; check < lastvisplane; check++)
                    237:        {
                    238:                if(height == check->height
                    239:                && picnum == check->picnum
                    240:                && lightlevel == check->lightlevel
                    241:                && special == check->special)
                    242:                        break;
                    243:        }
                    244: 
                    245:        if(check < lastvisplane)
                    246:        {
                    247:                return(check);
                    248:        }
                    249: 
                    250:        if(lastvisplane-visplanes == MAXVISPLANES)
                    251:        {
                    252:                I_Error("R_FindPlane: no more visplanes");
                    253:        }
                    254: 
                    255:        lastvisplane++;
                    256:        check->height = height;
                    257:        check->picnum = picnum;
                    258:        check->lightlevel = lightlevel;
                    259:        check->special = special;
                    260:        check->minx = SCREENWIDTH;
                    261:        check->maxx = -1;
1.1.1.2 ! root      262:        memset(check->top, 0xff, sizeof(check->top));
1.1       root      263:        return(check);
                    264: }
                    265: 
1.1.1.2 ! root      266: //==========================================================================
        !           267: //
        !           268: // R_CheckPlane
        !           269: //
        !           270: //==========================================================================
1.1       root      271: 
1.1.1.2 ! root      272: visplane_t *R_CheckPlane(visplane_t *pl, int start, int stop)
1.1       root      273: {
1.1.1.2 ! root      274:        int intrl, intrh;
        !           275:        int unionl, unionh;
        !           276:        int x;
        !           277: 
        !           278:        if(start < pl->minx)
1.1       root      279:        {
                    280:                intrl = pl->minx;
                    281:                unionl = start;
                    282:        }
                    283:        else
                    284:        {
                    285:                unionl = pl->minx;
                    286:                intrl = start;
                    287:        }
1.1.1.2 ! root      288:        if(stop > pl->maxx)
1.1       root      289:        {
                    290:                intrh = pl->maxx;
                    291:                unionh = stop;
                    292:        }
                    293:        else
                    294:        {
                    295:                unionh = pl->maxx;
                    296:                intrh = stop;
                    297:        }
                    298: 
1.1.1.2 ! root      299:        for(x = intrl; x <= intrh; x++)
        !           300:        {
        !           301:                if(pl->top[x] != 0xff)
        !           302:                {
1.1       root      303:                        break;
1.1.1.2 ! root      304:                }
        !           305:        }
1.1       root      306: 
1.1.1.2 ! root      307:        if(x > intrh)
1.1       root      308:        {
                    309:                pl->minx = unionl;
                    310:                pl->maxx = unionh;
1.1.1.2 ! root      311:                return pl; // use the same visplane
1.1       root      312:        }
                    313: 
1.1.1.2 ! root      314:        // Make a new visplane
1.1       root      315:        lastvisplane->height = pl->height;
                    316:        lastvisplane->picnum = pl->picnum;
                    317:        lastvisplane->lightlevel = pl->lightlevel;
                    318:        lastvisplane->special = pl->special;
                    319:        pl = lastvisplane++;
                    320:        pl->minx = start;
                    321:        pl->maxx = stop;
1.1.1.2 ! root      322:        memset(pl->top, 0xff, sizeof(pl->top));
        !           323: 
1.1       root      324:        return pl;
                    325: }
                    326: 
1.1.1.2 ! root      327: //==========================================================================
        !           328: //
        !           329: // R_MakeSpans
        !           330: //
        !           331: //==========================================================================
1.1       root      332: 
1.1.1.2 ! root      333: void R_MakeSpans(int x, int t1, int b1, int t2, int b2)
1.1       root      334: {
1.1.1.2 ! root      335:        while(t1 < t2 && t1 <= b1)
1.1       root      336:        {
1.1.1.2 ! root      337:                R_MapPlane(t1, spanstart[t1], x-1);
1.1       root      338:                t1++;
                    339:        }
1.1.1.2 ! root      340:        while(b1 > b2 && b1 >= t1)
1.1       root      341:        {
1.1.1.2 ! root      342:                R_MapPlane(b1, spanstart[b1], x-1);
1.1       root      343:                b1--;
                    344:        }
1.1.1.2 ! root      345:        while(t2 < t1 && t2 <= b2)
1.1       root      346:        {
                    347:                spanstart[t2] = x;
                    348:                t2++;
                    349:        }
1.1.1.2 ! root      350:        while(b2 > b1 && b2 >= t2)
1.1       root      351:        {
                    352:                spanstart[b2] = x;
                    353:                b2--;
                    354:        }
                    355: }
                    356: 
1.1.1.2 ! root      357: //==========================================================================
        !           358: //
        !           359: // R_DrawPlanes
        !           360: //
        !           361: //==========================================================================
1.1       root      362: 
1.1.1.2 ! root      363: #define SKYTEXTUREMIDSHIFTED 200
1.1       root      364: 
1.1.1.2 ! root      365: void R_DrawPlanes(void)
1.1       root      366: {
1.1.1.2 ! root      367:        visplane_t *pl;
        !           368:        int light;
        !           369:        int x, stop;
        !           370:        int angle;
1.1       root      371:        byte *tempSource;
1.1.1.2 ! root      372:        byte *source;
        !           373:        byte *source2;
1.1       root      374:        byte *dest;
                    375:        int count;
1.1.1.2 ! root      376:        int offset;
        !           377:        int skyTexture;
        !           378:        int offset2;
        !           379:        int skyTexture2;
        !           380:        int scrollOffset;
        !           381: 
        !           382:        extern byte *ylookup[MAXHEIGHT];
        !           383:        extern int columnofs[MAXWIDTH];
1.1       root      384: 
                    385: #ifdef RANGECHECK
1.1.1.2 ! root      386:        if(ds_p-drawsegs > MAXDRAWSEGS)
        !           387:        {
        !           388:                I_Error("R_DrawPlanes: drawsegs overflow (%i)", ds_p-drawsegs);
        !           389:        }
        !           390:        if(lastvisplane-visplanes > MAXVISPLANES)
        !           391:        {
        !           392:                I_Error("R_DrawPlanes: visplane overflow (%i)",
        !           393:                        lastvisplane-visplanes);
        !           394:        }
        !           395:        if(lastopening-openings > MAXOPENINGS)
        !           396:        {
        !           397:                I_Error("R_DrawPlanes: opening overflow (%i)",
        !           398:                        lastopening-openings);
        !           399:        }
1.1       root      400: #endif
                    401: 
1.1.1.2 ! root      402:        for(pl = visplanes; pl < lastvisplane; pl++)
1.1       root      403:        {
1.1.1.2 ! root      404:                if(pl->minx > pl->maxx)
1.1       root      405:                {
1.1.1.2 ! root      406:                        continue;
        !           407:                }
        !           408:                if(pl->picnum == skyflatnum)
        !           409:                { // Sky flat
        !           410:                        if(DoubleSky)
        !           411:                        { // Render 2 layers, sky 1 in front
        !           412:                                offset = Sky1ColumnOffset>>16;
        !           413:                                skyTexture = texturetranslation[Sky1Texture];
        !           414:                                offset2 = Sky2ColumnOffset>>16;
        !           415:                                skyTexture2 = texturetranslation[Sky2Texture];
        !           416:                                for(x = pl->minx; x <= pl->maxx; x++)
1.1       root      417:                                {
1.1.1.2 ! root      418:                                        dc_yl = pl->top[x];
        !           419:                                        dc_yh = pl->bottom[x];
        !           420:                                        if(dc_yl <= dc_yh)
1.1       root      421:                                        {
1.1.1.2 ! root      422:                                                count = dc_yh-dc_yl;
        !           423:                                                if(count < 0)
        !           424:                                                {
        !           425:                                                        return;
        !           426:                                                }
        !           427:                                                angle = (viewangle+xtoviewangle[x])
        !           428:                                                        >>ANGLETOSKYSHIFT;
        !           429:                                                source = R_GetColumn(skyTexture, angle+offset)
        !           430:                                                        +SKYTEXTUREMIDSHIFTED+(dc_yl-centery);
        !           431:                                                source2 = R_GetColumn(skyTexture2, angle+offset2)
        !           432:                                                        +SKYTEXTUREMIDSHIFTED+(dc_yl-centery);
        !           433:                                                dest = ylookup[dc_yl]+columnofs[x];
        !           434:                                                do
        !           435:                                                {
        !           436:                                                        if(*source)
        !           437:                                                        {
        !           438:                                                                *dest = *source++;
        !           439:                                                                source2++;
        !           440:                                                        }
        !           441:                                                        else
        !           442:                                                        {
        !           443:                                                                *dest = *source2++;
        !           444:                                                                source++;
        !           445:                                                        }
        !           446:                                                        dest += SCREENWIDTH;
        !           447:                                                } while(count--);
        !           448:                                        }
1.1       root      449:                                }
1.1.1.2 ! root      450:                                continue; // Next visplane
        !           451:                        }
        !           452:                        else
        !           453:                        { // Render single layer
        !           454:                                if(pl->special == 200)
        !           455:                                { // Use sky 2
        !           456:                                        offset = Sky2ColumnOffset>>16;
        !           457:                                        skyTexture = texturetranslation[Sky2Texture];
        !           458:                                }
        !           459:                                else
        !           460:                                { // Use sky 1
        !           461:                                        offset = Sky1ColumnOffset>>16;
        !           462:                                        skyTexture = texturetranslation[Sky1Texture];
        !           463:                                }
        !           464:                                for(x = pl->minx; x <= pl->maxx; x++)
        !           465:                                {
        !           466:                                        dc_yl = pl->top[x];
        !           467:                                        dc_yh = pl->bottom[x];
        !           468:                                        if(dc_yl <= dc_yh)
        !           469:                                        {
        !           470:                                                count = dc_yh-dc_yl;
        !           471:                                                if(count < 0)
        !           472:                                                {
        !           473:                                                        return;
        !           474:                                                }
        !           475:                                                angle = (viewangle+xtoviewangle[x])
        !           476:                                                        >>ANGLETOSKYSHIFT;
        !           477:                                                source = R_GetColumn(skyTexture, angle+offset)
        !           478:                                                        +SKYTEXTUREMIDSHIFTED+(dc_yl-centery);
        !           479:                                                dest = ylookup[dc_yl]+columnofs[x];
        !           480:                                                do
        !           481:                                                {
        !           482:                                                        *dest = *source++;
        !           483:                                                        dest += SCREENWIDTH;
        !           484:                                                } while(count--);
        !           485:                                        }
        !           486:                                }
        !           487:                                continue; // Next visplane
1.1       root      488:                        }
                    489:                }
1.1.1.2 ! root      490:                // Regular flat
        !           491:                tempSource = W_CacheLumpNum(firstflat+
1.1       root      492:                        flattranslation[pl->picnum], PU_STATIC);
1.1.1.2 ! root      493:                scrollOffset = leveltime>>1&63;
1.1       root      494:                switch(pl->special)
1.1.1.2 ! root      495:                { // Handle scrolling flats
        !           496:                        case 201: case 202: case 203: // Scroll_North_xxx
        !           497:                                ds_source = tempSource+((scrollOffset
        !           498:                                        <<(pl->special-201)&63)<<6);
1.1       root      499:                                break;
1.1.1.2 ! root      500:                        case 204: case 205: case 206: // Scroll_East_xxx
        !           501:                                ds_source = tempSource+((63-scrollOffset)
        !           502:                                        <<(pl->special-204)&63);
1.1       root      503:                                break;
1.1.1.2 ! root      504:                        case 207: case 208: case 209: // Scroll_South_xxx
        !           505:                                ds_source = tempSource+(((63-scrollOffset)
        !           506:                                        <<(pl->special-207)&63)<<6);
1.1       root      507:                                break;
1.1.1.2 ! root      508:                        case 210: case 211: case 212: // Scroll_West_xxx
        !           509:                                ds_source = tempSource+(scrollOffset
        !           510:                                        <<(pl->special-210)&63);
1.1       root      511:                                break;
1.1.1.2 ! root      512:                        case 213: case 214: case 215: // Scroll_NorthWest_xxx
        !           513:                                ds_source = tempSource+(scrollOffset
        !           514:                                        <<(pl->special-213)&63)+((scrollOffset
        !           515:                                        <<(pl->special-213)&63)<<6);
        !           516:                                break;
        !           517:                        case 216: case 217: case 218: // Scroll_NorthEast_xxx
        !           518:                                ds_source = tempSource+((63-scrollOffset)
        !           519:                                        <<(pl->special-216)&63)+((scrollOffset
        !           520:                                        <<(pl->special-216)&63)<<6);
        !           521:                                break;
        !           522:                        case 219: case 220: case 221: // Scroll_SouthEast_xxx
        !           523:                                ds_source = tempSource+((63-scrollOffset)
        !           524:                                        <<(pl->special-219)&63)+(((63-scrollOffset)
        !           525:                                        <<(pl->special-219)&63)<<6);
        !           526:                                break;
        !           527:                        case 222: case 223: case 224: // Scroll_SouthWest_xxx
        !           528:                                ds_source = tempSource+(scrollOffset
        !           529:                                        <<(pl->special-222)&63)+(((63-scrollOffset)
        !           530:                                        <<(pl->special-222)&63)<<6);
1.1       root      531:                                break;
                    532:                        default:
                    533:                                ds_source = tempSource;
1.1.1.2 ! root      534:                                break;
1.1       root      535:                }
                    536:                planeheight = abs(pl->height-viewz);
                    537:                light = (pl->lightlevel >> LIGHTSEGSHIFT)+extralight;
1.1.1.2 ! root      538:                if(light >= LIGHTLEVELS)
        !           539:                {
1.1       root      540:                        light = LIGHTLEVELS-1;
1.1.1.2 ! root      541:                }
        !           542:                if(light < 0)
        !           543:                {
1.1       root      544:                        light = 0;
1.1.1.2 ! root      545:                }
1.1       root      546:                planezlight = zlight[light];
                    547: 
                    548:                pl->top[pl->maxx+1] = 0xff;
                    549:                pl->top[pl->minx-1] = 0xff;
1.1.1.2 ! root      550: 
        !           551:                stop = pl->maxx+1;
        !           552:                for(x = pl->minx; x <= stop; x++)
        !           553:                {
        !           554:                        R_MakeSpans(x, pl->top[x-1], pl->bottom[x-1],
        !           555:                                pl->top[x], pl->bottom[x]);
        !           556:                }
        !           557:                Z_ChangeTag(tempSource, PU_CACHE);
1.1       root      558:        }
                    559: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.