Mercurial > hg > dmlib
diff dmq3d.c @ 241:3bff024a91be
Move 3D line/sprite renderer to separate module.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 09 Oct 2012 13:02:55 +0300 |
parents | |
children | a9d500e5698d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmq3d.c Tue Oct 09 13:02:55 2012 +0300 @@ -0,0 +1,308 @@ +#include "dmq3d.h" +#include "dmimage.h" + + +#define DM_DRAWLINE_NAME dmDrawLineSpec +#define DM_DRAWLINE_DST_BYTES 4 +#define DM_DRAWLINE_DST_TYPE DMRGBA32 +#define DM_DRAWLINE_ARGS , SDL_Surface *bmp +#define DM_DRAWLINE_INIT const int px = bmp->w / 2, py = bmp->h / 2; +#define DM_DRAWLINE_INNER \ + dmUnscaledBlitSurface32to32Transparent(bmp, x0-px, y0-py, screen); +#define DM_DRAWLINE_SPEC +#include "dmdrawline.h" + + +static int dmFind3DBitmap(int nitems, DM3DBitmap *items, DM3DBitmap *item) +{ + int i; + for (i = 0; i < nitems; i++) + if (strcmp(item->name, items[i].name) == 0) + return i; + return -1; +} + +#define DM_FIND_ITEM_FUNC(NAME, TYPE) \ +static int dmFind3D ## NAME (int nitems, TYPE *items, TYPE *item) \ +{ \ + int i; \ + for (i = 0; i < nitems; i++) \ + if (memcmp(item, items+i, sizeof(TYPE)) == 0) \ + return i; \ + return -1; \ +} + +#define DM_ADD_ITEM_FUNC(NAME, TYPE) \ +static int dmAdd3D ## NAME (int *nitems, int *nalloc, TYPE **items, TYPE *item, int *res) \ +{ \ + int tmp; \ + if ((tmp = dmFind3D ## NAME (*nitems, *items, item)) >= 0) \ + { \ + if (res != NULL) *res = tmp; \ + return DMERR_OK; \ + } \ + if ((*nitems) + 1 >= *nalloc) \ + { \ + (*nalloc) += 16; \ + if ((*items = dmRealloc(*items, *nalloc * sizeof(TYPE))) == NULL) \ + return DMERR_MALLOC; \ + } \ + memcpy((*items) + (*nitems), item, sizeof(TYPE)); \ + if (res != NULL) *res = *nitems; \ + (*nitems)++; \ + return DMERR_OK; \ +} + +DM_FIND_ITEM_FUNC(Vertex, DMVector) +DM_FIND_ITEM_FUNC(Line, DM3DLine) +DM_FIND_ITEM_FUNC(Sprite, DM3DSprite) + +DM_ADD_ITEM_FUNC(Vertex, DMVector) +DM_ADD_ITEM_FUNC(Line, DM3DLine) +DM_ADD_ITEM_FUNC(Sprite, DM3DSprite) +DM_ADD_ITEM_FUNC(Bitmap, DM3DBitmap) + + +int dmAdd3DLineSpriteModelVertex(DM3DLineSpriteModel *model, DMVector *v, int *index) +{ + return dmAdd3DVertex(&model->nvertices, &model->nvertexalloc, + &model->vertices, v, index); +} + +int dmAdd3DLineSpriteModelLine(DM3DLineSpriteModel *model, DM3DLine *v, int *index) +{ + return dmAdd3DLine(&model->nlines, &model->nlinesalloc, + &model->lines, v, index); +} + +int dmAdd3DLineSpriteModelSprite(DM3DLineSpriteModel *model, DM3DSprite *v, int *index) +{ + return dmAdd3DSprite(&model->nsprites, &model->nspritesalloc, + &model->sprites, v, index); +} + +int dmAdd3DLineSpriteModelBitmap(DM3DLineSpriteModel *model, DM3DBitmap *v, int *index) +{ + return dmAdd3DBitmap(&model->nbitmaps, &model->nbitmapsalloc, + &model->bitmaps, v, index); +} + + +static inline DMFloat dmPX(DMVector p) +{ + return 320 + p.x * 250.0f / (p.z + 501.0f); +} + + +static inline DMFloat dmPY(DMVector p) +{ + return 200 + p.y * 250.0f / (p.z + 501.0f); +} + + +void dmDraw3DLineSpriteModel(SDL_Surface *screen, DM3DLineSpriteModel *model, DMVector *pos, DMMatrix *mat, SDL_Surface *fbmap, Uint32 lcol) +{ + int i; + for (i = 0; i < model->nlines; i++) + { + DM3DLine *line = &model->lines[i]; + DMVector pv[2]; + dm_vector_add_r(&pv[0], &model->vertices[line->v1], pos); + dm_vector_add_r(&pv[1], &model->vertices[line->v2], pos); + dm_vector_mul_by_mat_n(pv, 2, mat); + + if (line->type > 1) + dmDrawLineSpec(screen, dmPX(pv[0]), dmPY(pv[0]), dmPX(pv[1]), dmPY(pv[1]), lcol, fbmap); + else + dmDrawLine32(screen, dmPX(pv[0]), dmPY(pv[0]), dmPX(pv[1]), dmPY(pv[1]), lcol); + } + + for (i = 0; i < model->nsprites; i++) + { + DM3DSprite *sprite = &model->sprites[i]; + DM3DBitmap *bmp = &model->bitmaps[sprite->bitmap]; + DMVector pv, pt; + dm_vector_add_r(&pt, &model->vertices[sprite->v], pos); + dm_vector_mul_by_mat(&pv, &pt, mat); + dmUnscaledBlitSurface32to32Transparent(bmp->img, dmPX(pv), dmPY(pv), screen); + } +} + + +static char *dmSkipWhitespace(char *line, BOOL invert) +{ + if (invert) + for (; *line && !isspace(*line); line++); + else + for (; *line && isspace(*line); line++); + return line; +} + + +static char *dmSkipUntil(char *line, char ch) +{ + for (; *line && *line != ch; line++); + return line; +} + + +static BOOL dmReadCoordinate(char **line, float *value, BOOL next) +{ + *line = dmSkipWhitespace(*line, FALSE); + if (sscanf(*line, "%f", value) != 1) return FALSE; + if (next) + { + *line = dmSkipUntil(*line, ','); + if (**line != ',') return FALSE; + *(*line)++; + } + else + *line = dmSkipWhitespace(*line, TRUE); + + return TRUE; +} + +static BOOL dmReadLineSegments(char *line, DM3DLineSpriteModel *model) +{ + int nvertices, vertex, type; + int *indices = NULL; + if (sscanf(line+1, "%d", &nvertices) != 1) + { + dmError("No # of segments @ '%s'\n", line); + goto error; + } + + if ((indices = dmMalloc(sizeof(int) * (nvertices+1))) == NULL) + goto error; + + line = dmSkipWhitespace(line, TRUE); + for (vertex = 0; vertex <= nvertices; vertex++) + { + DMVector p; + if (!dmReadCoordinate(&line, &p.x, TRUE)) return FALSE; + if (!dmReadCoordinate(&line, &p.y, TRUE)) return FALSE; + if (!dmReadCoordinate(&line, &p.z, FALSE)) return FALSE; + if (dmAdd3DLineSpriteModelVertex(model, &p, &indices[vertex]) != DMERR_OK) + goto error; + line = dmSkipWhitespace(line, FALSE); + } + + if (sscanf(line, "%d", &type) != 1) + { + dmError("No line type @ '%s'\n", line); + goto error; + } + + for (vertex = 1; vertex <= nvertices; vertex++) + { + DM3DLine line; + line.v1 = indices[vertex - 1]; + line.v2 = indices[vertex]; + line.type = type; + if (dmAdd3DLineSpriteModelLine(model, &line, NULL) != DMERR_OK) + goto error; + } + + return TRUE; +error: + dmFree(indices); + return FALSE; +} + +static BOOL dmReadSprite(char *line, DM3DLineSpriteModel *model) +{ + DMVector pt; + DM3DSprite spr; + + line++; + if (!dmReadCoordinate(&line, &pt.x, TRUE)) return FALSE; + if (!dmReadCoordinate(&line, &pt.y, TRUE)) return FALSE; + if (!dmReadCoordinate(&line, &pt.z, FALSE)) return FALSE; + line = dmSkipWhitespace(line, FALSE); + if (*line != 'B') + { + dmError("No bitmap definition found for sprite.\n"); + return FALSE; + } + + spr.bitmap = atoi(line + 1); + + if (dmAdd3DLineSpriteModelVertex(model, &pt, &spr.v) != DMERR_OK) + return FALSE; + + if (dmAdd3DLineSpriteModelSprite(model, &spr, NULL) != DMERR_OK) + return FALSE; + + return TRUE; +} + +static BOOL dmReadBitmap(char *line, DM3DLineSpriteModel *model) +{ + DM3DBitmap bmp, *rbmp; + int index; + + strncpy(bmp.name, line + 1, sizeof(bmp.name)); + bmp.img = NULL; + + if (dmAdd3DLineSpriteModelBitmap(model, &bmp, &index) != DMERR_OK) + return FALSE; + + rbmp = &(model->bitmaps[index]); + if (rbmp->img == NULL) + { + DMResource *res = dmf_create_stdio(rbmp->name, "rb"); + if (res == NULL) + { + dmError("Could not open resource file '%s'.\n", rbmp->name); + return FALSE; + } + rbmp->img = dmLoadImage(res); + dmf_close(res); + if (rbmp->img == NULL) + { + dmError("Could not load image file '%s'.\n", rbmp->name); + return FALSE; + } + } + fprintf(stderr, "loaded '%s': %d: %p\n", rbmp->name, index, rbmp->img); + return TRUE; +} + + +int dmRead3DLineSpriteModel(DMResource *f, DM3DLineSpriteModel *model) +{ + char line[512]; + + memset(model, 0, sizeof(*model)); + + while (dmfgets(line, sizeof(line), f) != NULL) + { + char *start = dmSkipWhitespace(line, FALSE); + switch (*start) + { + case 0: + case '#': + break; + + case 'B': + if (!dmReadBitmap(start, model)) + return DMERR_INVALID_DATA; + break; + + case 'L': + if (!dmReadLineSegments(start, model)) + return DMERR_INVALID_DATA; + break; + + case 'S': + if (!dmReadSprite(start, model)) + return DMERR_INVALID_DATA; + break; + + default: + break; + } + } + + return DMERR_OK; +}