Omnimaga

Calculator Community => TI Calculators => Calculator C => Topic started by: Matrefeytontias on March 25, 2013, 01:01:56 pm

Title: [Ndless] Problems with hoffa and t0xic_kitt3n' mode7 engine
Post by: Matrefeytontias on March 25, 2013, 01:01:56 pm
Hey guys,

I'm currently adapting F-Zero to use with the hoffa and t_k' mode7 engine, but I can't make it display a simple rotoscaled map. I didn't ask them because there's been a while they didn't even log in <_<

So, I adapted a little bit the engine to make it work with non-square maps, but it keep not working.

Original m7.c :
Code: [Select]
#include <os.h>
#include <SDL.h>

#include "m7.h"

void m7BuildLut(m7Vec_t lut[M7_SCREEN_HEIGHT]) {
    int screenRow;
    for (screenRow = 0; screenRow < M7_SCREEN_HEIGHT; ++screenRow) {
        float cameraV = (((float)screenRow / (float)M7_SCREEN_HEIGHT) * 2.0F - 1.0F);

        float rayX = M7_VIEW_PLANE_H;
        float rayY = 1.0F;
        float rayZ = M7_VIEW_PLANE_V * cameraV;

        float intersectY = (M7_VIEW_HEIGHT / rayZ) * rayY;
        float intersectX = (M7_VIEW_HEIGHT / rayZ) * rayX;

        lut[screenRow].x = M7_FLOAT_TO_FIX(intersectX);
        lut[screenRow].y = M7_FLOAT_TO_FIX(intersectY);
    }
}

void m7LoadTex(Uint8 tex[M7_NUM_TEX][M7_TEX_SIZE][M7_TEX_SIZE], ...) {
    va_list ap;
    int i, j, k;

    va_start(ap, tex);
    for (i = 0; i < M7_NUM_TEX; ++i) {
        SDL_Surface* surf = va_arg(ap, SDL_Surface*);
        for (j = 0; j < M7_TEX_SIZE; j++)
            for (k = 0; k < M7_TEX_SIZE; k++)
                tex[i][j][k] = nSDL_GetPixel(surf, k, j);
    }
    va_end(ap);
}

void m7Render(SDL_Surface *screen,
              m7Vec_t lut[M7_SCREEN_HEIGHT],
              Uint8 tilemap[M7_MAP_SIZE][M7_MAP_SIZE],
              Uint8 tex[M7_NUM_TEX][M7_TEX_SIZE][M7_TEX_SIZE],
              m7Vec_t pos,
              Sint32 heading) {
    int screenX, screenY;
    for (screenY = (M7_SCREEN_HEIGHT / 2) + 1; screenY < M7_SCREEN_HEIGHT; ++screenY) {
        m7Vec_t map = lut[screenY];
        m7Vec_t mapXStep = {-map.x / (M7_SCREEN_WIDTH / 2), 0};
       
        Sint32 sinHeading = m7SinLut(heading);
        Sint32 cosHeading = m7CosLut(heading);
       
        m7RotateVec(&map, sinHeading, cosHeading);
        m7RotateVec(&mapXStep, sinHeading, cosHeading);
       
        map.x += pos.x;
        map.y += pos.y;
       
        for (screenX = 0; screenX < M7_SCREEN_WIDTH; ++screenX) {
            Uint8 color = 0;

            if (map.x >= 0 && map.x < M7_INT_TO_FIX(M7_MAP_SIZE)
             && map.y >= 0 && map.y < M7_INT_TO_FIX(M7_MAP_SIZE))
                color = tex[(int)tilemap[map.y >> M7_TEX_SIZE]
                                        [map.x >> M7_TEX_SIZE]]
                           [(map.y & 0xFFFF) >> 12]
                           [(map.x & 0xFFFF) >> 12];

            map.x += mapXStep.x;
            map.y += mapXStep.y;

            M7_SET_PIXEL8(screenX, screenY, color);
        }
    }
    SDL_UpdateRect(screen, 0, M7_SCREEN_HEIGHT / 2, M7_SCREEN_WIDTH, M7_SCREEN_HEIGHT / 2);
}
(m7.h only contains some very basic defines)

Modified m7.c :
Code: [Select]
#include <os.h>
#include <SDL.h>

#include "m7.h"

void m7BuildLut(m7Vec_t lut[M7_SCREEN_HEIGHT]) {
    int screenRow;
    for (screenRow = 0; screenRow < M7_SCREEN_HEIGHT; ++screenRow) {
        float cameraV = (((float)screenRow / (float)M7_SCREEN_HEIGHT) * 2.0F - 1.0F);

        float rayX = M7_VIEW_PLANE_H;
        float rayY = 1.0F;
        float rayZ = M7_VIEW_PLANE_V * cameraV;

        float intersectY = (M7_VIEW_HEIGHT / rayZ) * rayY;
        float intersectX = (M7_VIEW_HEIGHT / rayZ) * rayX;

        lut[screenRow].x = M7_FLOAT_TO_FIX(intersectX);
        lut[screenRow].y = M7_FLOAT_TO_FIX(intersectY);
    }
}

void m7LoadTex(Uint8 tex[M7_NUM_TEX][M7_TEX_SIZE][M7_TEX_SIZE], ...) {
    va_list ap;
    int i, j, k;

    va_start(ap, tex);
    for (i = 0; i < M7_NUM_TEX; ++i) {
        SDL_Surface* surf = va_arg(ap, SDL_Surface*);
        for (j = 0; j < M7_TEX_SIZE; j++)
            for (k = 0; k < M7_TEX_SIZE; k++)
                tex[i][j][k] = nSDL_GetPixel(surf, k, j);
    }
    va_end(ap);
}

void m7LoadTexArray(Uint8 tex[M7_NUM_TEX][M7_TEX_SIZE][M7_TEX_SIZE], SDL_Surface *src)
{
int i,j,k;
for(i = 0; i < M7_NUM_TEX; i++)
for(k = 0; k < M7_TEX_SIZE; k++)
for(j = 0; j < M7_TEX_SIZE; j++)
tex[i][k][j] = nSDL_GetPixel(src, j, i * M7_TEX_SIZE + k);
}

void m7Render(SDL_Surface *screen,
              m7Vec_t lut[M7_SCREEN_HEIGHT],
              Uint8 **tilemap,
              Uint8 tex[M7_NUM_TEX][M7_TEX_SIZE][M7_TEX_SIZE],
              m7Vec_t pos,
              Sint32 heading,
  Uint8 mapWidth,
  Uint8 mapHeight) {
    int screenX, screenY;
    for (screenY = (M7_SCREEN_HEIGHT / 2) + 1; screenY < M7_SCREEN_HEIGHT; ++screenY) {
        m7Vec_t map = lut[screenY];
        m7Vec_t mapXStep = {-map.x / (M7_SCREEN_WIDTH / 2), 0};
       
        Sint32 sinHeading = m7SinLut(heading);
        Sint32 cosHeading = m7CosLut(heading);
       
        m7RotateVec(&map, sinHeading, cosHeading);
        m7RotateVec(&mapXStep, sinHeading, cosHeading);
       
        map.x += pos.x;
        map.y += pos.y;
       
        for (screenX = 0; screenX < M7_SCREEN_WIDTH; ++screenX) {
            Uint8 color = 0;

            if (map.x >= 0 && map.x < M7_INT_TO_FIX(mapWidth)
             && map.y >= 0 && map.y < M7_INT_TO_FIX(mapHeight))
                color = tex[(int)tilemap[map.y >> M7_TEX_SIZE]
                                        [map.x >> M7_TEX_SIZE]]
                           [(map.y & 0xFFFF) >> 12]
                           [(map.x & 0xFFFF) >> 12];

            map.x += mapXStep.x;
            map.y += mapXStep.y;

            M7_SET_PIXEL8(screenX, screenY, color);
        }
    }
    SDL_UpdateRect(screen, 0, M7_SCREEN_HEIGHT / 2, M7_SCREEN_WIDTH, M7_SCREEN_HEIGHT / 2);
}

demo.c (from the engine's zip, works) :
Code: [Select]
#include <os.h>
#include <SDL/SDL.h>

#include "m7.h"
#include "gfx.h"

SDL_Surface *screen;

SDL_Surface *loadTex(unsigned short *data) {
    SDL_Surface *tex, *tmp;
    tmp = nSDL_LoadImage(data);
    tex = SDL_DisplayFormat(tmp);
    SDL_FreeSurface(tmp);
    return tex;
}

int main(void) {
    m7Vec_t lut[M7_SCREEN_HEIGHT];
    Uint8 tilemap[M7_MAP_SIZE][M7_MAP_SIZE];
    Uint8 tex[M7_NUM_TEX][M7_TEX_SIZE][M7_TEX_SIZE];
    m7Vec_t pos = {M7_INT_TO_FIX(2), M7_INT_TO_FIX(4)};
    Sint32 heading = 0;

    SDL_Surface *texMushroom, *texFB, *texCartman, *texYoshi;
    nSDL_Font *font;
    const SDL_VideoInfo *info;
    Uint32 curTime = 0;
    Uint32 oldTime = 0;
    int fps = 0;
    int num_frames = 0;
    int done = 0;
    int i, j;

    SDL_Init(SDL_INIT_VIDEO);
    screen = SDL_SetVideoMode(M7_SCREEN_WIDTH, M7_SCREEN_HEIGHT, M7_BPP, SDL_SWSURFACE);
    font = nSDL_LoadFont(NSDL_FONT_TINYTYPE, 255, 255, 255);
    texMushroom = loadTex(ntiMushroom);
    texFB = loadTex(ntiFB);
    texCartman = loadTex(ntiCartman);
    texYoshi = loadTex(ntiYoshi);
    SDL_FillRect(screen, NULL, 0);
    info = SDL_GetVideoInfo();
    nSDL_DrawString(screen, font, 0, 0, "M7 engine test\nnSDL %s\n%dx%d\n%d-bit/%d-bit",
                    NSDL_VERSION, info->current_w, info->current_h, info->vfmt->BitsPerPixel, is_cx ? 16 : 4);
    SDL_Flip(screen);

    srand(42);
    for (i = 0; i < M7_MAP_SIZE; ++i)
        for (j = 0; j < M7_MAP_SIZE; ++j)
            tilemap[i][j] = rand() % 4;

    m7BuildLut(lut);
    m7LoadTex(tex, texMushroom, texFB, texCartman, texYoshi);

    while(!done) {
        m7Vec_t moveDist = {M7_INT_TO_FIX(0), M7_FLOAT_TO_FIX(0.25)};
        SDL_Rect fpsRect = {M7_SCREEN_WIDTH - 40, 0, 40, 8};

        m7RotateVec(&moveDist, m7SinLut(heading), m7CosLut(heading));

        if (isKeyPressed(KEY_NSPIRE_8)) m7AddVec(&pos, &moveDist);
        if (isKeyPressed(KEY_NSPIRE_2)) m7SubVec(&pos, &moveDist);
        if (isKeyPressed(KEY_NSPIRE_6)) m7AddVec(&pos, m7RotateVec(&moveDist, M7_INT_TO_FIX(1), 0));
        if (isKeyPressed(KEY_NSPIRE_4)) m7SubVec(&pos, m7RotateVec(&moveDist, M7_INT_TO_FIX(1), 0));
        if (isKeyPressed(KEY_NSPIRE_9)) heading -= 0x400;
        if (isKeyPressed(KEY_NSPIRE_7)) heading += 0x400;
        if (isKeyPressed(KEY_NSPIRE_ESC)) done = 1;

        m7Render(screen, lut, tilemap, tex, pos, heading);

        SDL_FillRect(screen, &fpsRect, 0);
        nSDL_DrawString(screen, font, fpsRect.x, fpsRect.y, "%d FPS", fps);
        SDL_UpdateRect(screen, fpsRect.x, fpsRect.y, fpsRect.w, fpsRect.h);
        curTime = SDL_GetTicks();
        if(curTime - oldTime <= 993) /* Clock set to 993 Hz by nSDL */
            ++num_frames;
        else {
            fps = num_frames;
            num_frames = 0;
            oldTime = curTime;
        }
    }

    SDL_FreeSurface(texYoshi);
    SDL_FreeSurface(texCartman);
    SDL_FreeSurface(texFB);
    SDL_FreeSurface(texMushroom);
    nSDL_FreeFont(font);
    SDL_Quit();

    return 0;
}

main.c (mine, doesn't work) :
Code: [Select]
#include <os.h>
#include <SDL.h>
#include "m7.h"

SDL_Surface *loadTex(unsigned short *data)
{
SDL_Surface *tex, *temp;
temp = nSDL_LoadImage(data);
tex = SDL_DisplayFormat(temp);
SDL_FreeSurface(temp);
return tex;
}

int main(int argc, char *argv[])
{
// Mode7-relative variables
m7Vec_t lut[M7_SCREEN_HEIGHT];
#include "muteCityTilemap.h"
#include "muteCityTileset.h"
#include "blueFalcon.h"
Uint8 finalTex[M7_NUM_TEX][M7_TEX_SIZE][M7_TEX_SIZE];
m7Vec_t pos = {M7_INT_TO_FIX(1), M7_INT_TO_FIX(1)};
Sint32 heading = 0;

SDL_Surface *screen, *shipSurface, *tiles;
SDL_Rect shipRect, shipSrcRect;

shipRect.x = 136;
shipRect.y = 190;

shipSrcRect.x = (shipSrcRect.y = 0);
shipSrcRect.w = 48;
shipSrcRect.h = 31;

SDL_Init(SDL_INIT_VIDEO);

int speed = 0, rotationSpeed = 0;

screen = SDL_SetVideoMode(M7_SCREEN_WIDTH, M7_SCREEN_HEIGHT, M7_BPP, SDL_SWSURFACE);

shipSurface = nSDL_LoadImage(blueFalconSprite);
SDL_SetColorKey(shipSurface, SDL_SRCCOLORKEY, SDL_MapRGB(shipSurface->format, 0xff, 0, 0xff));

tiles = loadTex(muteCityTileset);

m7BuildLut(lut);
m7LoadTexArray(finalTex, tiles);

while(1)
{
m7Vec_t moveDist = {M7_INT_TO_FIX(0), M7_FLOAT_TO_FIX(0.25)};

m7RotateVec(&moveDist, m7SinLut(heading), m7CosLut(heading));

if(isKeyPressed(KEY_NSPIRE_ESC)) break;
if(isKeyPressed(KEY_NSPIRE_DOWN)) m7SubVec(&pos, &moveDist);
if(isKeyPressed(KEY_NSPIRE_LEFT))
{
heading -= 0x400;
shipSrcRect.y = 62;
}
if(isKeyPressed(KEY_NSPIRE_RIGHT))
{
heading += 0x400;
shipSrcRect.y = 31;
}
if(!isKeyPressed(KEY_NSPIRE_LEFT) && !isKeyPressed(KEY_NSPIRE_RIGHT)) shipSrcRect.y = 0;
if(isKeyPressed(KEY_NSPIRE_UP)) m7AddVec(&pos, &moveDist);

m7Render(screen, lut, muteCityTilemap, finalTex, pos, heading, 792, 366);

}

SDL_FreeSurface(tiles);
SDL_FreeSurface(shipSurface);
SDL_Quit();

return 0;
}

The *.h I use are always image datas.

You can download the engine here : http://ourl.ca/18123/337001

If you can help me, I'd be glad :(
Title: Re: [Ndless] Problems with hoffa and t0xic_kitt3n' mode7 engine
Post by: Juju on March 25, 2013, 01:23:22 pm
What's the error exactly?
Title: Re: [Ndless] Problems with hoffa and t0xic_kitt3n' mode7 engine
Post by: Matrefeytontias on March 25, 2013, 01:24:08 pm
I really don't know. It compiles fine, but when I launch it on whatever Nspire, it crashes immediately.
Title: Re: [Ndless] Problems with hoffa and t0xic_kitt3n' mode7 engine
Post by: tr1p1ea on March 25, 2013, 01:28:04 pm
Did you successfully launch the unmodified version at any stage?
Title: Re: [Ndless] Problems with hoffa and t0xic_kitt3n' mode7 engine
Post by: Matrefeytontias on March 25, 2013, 01:28:56 pm
Yep I did, it works perfectly.
Title: Re: [Ndless] Problems with hoffa and t0xic_kitt3n' mode7 engine
Post by: hoffa on March 26, 2013, 09:09:11 pm
First of all in the engine there are a few hardcoded values that you have to live with, that's what allows good optimization. Look at the macros in the header and see if you have to change them (you should only need to change M7_NUM_TEX IIRC). A texture in the engine is a 16x16 bitmap, aka a tile. m7_LoadTex() adds M7_NUM_TEX 16x16 SDL_Surfaces to the main texture array that contains all of the tiles. Look at the demo I wrote, start from there and modify it bit by bit so you understand what you and the code are doing.

Also this line's wrong: tex[k][j] = nSDL_GetPixel(src, j, i * M7_TEX_SIZE + k); nSDL_GetPixel() takes x- and y-coordinates as input. But you shouldn't even have to write such a function, as m7_LoadTex() does just that (look at how it was done in the demo).

Greetings from a public library in Canberra.
Title: Re: [Ndless] Problems with hoffa and t0xic_kitt3n' mode7 engine
Post by: Matrefeytontias on March 26, 2013, 09:32:41 pm
I know what m7_LoadTex() does, but it needs one argument for each tile, I won't put 256 SDL_Surfaces in my program .__.


Also, the getPixel line is that way because the tilset is 8*2048.