nkeynes@1145: /** nkeynes@1145: * $Id$ nkeynes@1145: * nkeynes@1145: * Tile iterator ADT. Defines an iterator that can be used to iterate through nkeynes@1145: * a PVR2 tile list a polygon at a time. nkeynes@1145: * nkeynes@1145: * Note: The iterator functions are defined here to allow the compiler to nkeynes@1145: * inline them if it wants to, but it's not always beneficial to do so nkeynes@1145: * (hence we don't force them to be inlined) nkeynes@1145: * nkeynes@1145: * Copyright (c) 2010 Nathan Keynes. nkeynes@1145: * nkeynes@1145: * This program is free software; you can redistribute it and/or modify nkeynes@1145: * it under the terms of the GNU General Public License as published by nkeynes@1145: * the Free Software Foundation; either version 2 of the License, or nkeynes@1145: * (at your option) any later version. nkeynes@1145: * nkeynes@1145: * This program is distributed in the hope that it will be useful, nkeynes@1145: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@1145: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@1145: * GNU General Public License for more details. nkeynes@1145: */ nkeynes@1145: nkeynes@1145: #ifndef lxdream_tileiter_H nkeynes@1145: #define lxdream_tileiter_H 1 nkeynes@1145: nkeynes@1145: #include nkeynes@1145: #include "pvr2/pvr2.h" nkeynes@1145: nkeynes@1145: #ifdef __cplusplus nkeynes@1145: extern "C" { nkeynes@1145: #endif nkeynes@1145: nkeynes@1145: nkeynes@1145: /** nkeynes@1145: * tileiter: iterator over individual polygons in a tile list. nkeynes@1145: */ nkeynes@1145: typedef struct tileiter { nkeynes@1145: uint32_t *ptr; nkeynes@1145: unsigned strip_count; nkeynes@1145: unsigned poly_size; nkeynes@1145: uint32_t poly_addr; nkeynes@1145: } tileiter; nkeynes@1145: nkeynes@1145: nkeynes@1145: #define TILEITER_IS_MODIFIED(it) ((*(it).ptr) & 0x01000000) nkeynes@1145: #define TILEITER_IS_TRIANGLE(it) (((*(it).ptr) >> 29) == 4) nkeynes@1145: #define TILEITER_IS_QUAD(it) (((*(it).ptr) >> 29) == 5) nkeynes@1145: #define TILEITER_IS_POLY(it) (((*(it).ptr) >> 31) == 0) nkeynes@1145: nkeynes@1145: #define TILEITER_POLYADDR(it) ((it).poly_addr) nkeynes@1145: #define TILEITER_STRIPCOUNT(it) ((it).strip_count) nkeynes@1145: #define TILEITER_DONE(it) ((it).ptr == 0) nkeynes@1145: #define TILEITER_BEGIN(it, tileent) (tileiter_init(&it, tileent)) nkeynes@1145: #define TILEITER_NEXT(it) (tileiter_next(&it)) nkeynes@1145: #define FOREACH_TILE(it, seg) for( TILEITER_BEGIN(it, seg); !TILEITER_DONE(it); TILEITER_NEXT(it) ) nkeynes@1145: nkeynes@1145: nkeynes@1145: /** nkeynes@1145: * tileentryiter: iterator over entries in the tile list, where each entry is nkeynes@1145: * a polygon, triangle set, or quad set. nkeynes@1145: */ nkeynes@1145: typedef struct tileentryiter { nkeynes@1145: uint32_t *ptr; nkeynes@1145: unsigned strip_count; nkeynes@1145: } tileentryiter; nkeynes@1145: nkeynes@1145: #define TILEENTRYITER_POLYADDR(it) ((*((it).ptr)) & 0x001FFFFF) nkeynes@1145: #define TILEENTRYITER_STRIPCOUNT(it) ((it).strip_count) nkeynes@1145: #define TILEENTRYITER_DONE(it) ((it).ptr == 0) nkeynes@1145: #define TILEENTRYITER_BEGIN(it, tileent) (tileentryiter_init(&(it),tileent)) nkeynes@1145: #define TILEENTRYITER_NEXT(it) (tileentryiter_next(&(it))) nkeynes@1145: #define FOREACH_TILEENTRY(it,seg) for( TILEENTRYITER_BEGIN(it,seg); !TILEENTRYITER_DONE(it); TILEENTRYITER_NEXT(it) ) nkeynes@1145: nkeynes@1145: /**************************** tileiter functions ****************************/ nkeynes@1145: nkeynes@1145: /** nkeynes@1145: * Read the entry pointed to by it->ptr into the tileiter structure. If the nkeynes@1145: * entry if a list pointer or invalid entry, the pointer will first be nkeynes@1145: * updated to the next real entry. On end-of-list, sets ptr to NULL nkeynes@1145: */ nkeynes@1145: static void tileiter_read( tileiter *it ) nkeynes@1145: { nkeynes@1145: for(;;){ nkeynes@1145: uint32_t entry = *it->ptr; nkeynes@1145: uint32_t tag = entry >> 29; nkeynes@1153: if( tag == 0x07 ) { nkeynes@1153: if( tag & 0x10000000 ) { nkeynes@1153: it->ptr = NULL; nkeynes@1145: return; nkeynes@1145: } else { nkeynes@1153: it->ptr = (uint32_t *)(pvr2_main_ram + (entry&0x007FFFFF)); nkeynes@1153: it->poly_addr = -1; nkeynes@1153: entry = *it->ptr; nkeynes@1145: } nkeynes@1153: } else if( tag == 6 ) { nkeynes@1153: /* Illegal? Skip */ nkeynes@1153: it->ptr++; nkeynes@1153: } else if( tag & 0x04 ) { nkeynes@1153: int vertex_count = tag-1; /* 4 == tri, 5 == quad */ nkeynes@1153: int vertex_length = (entry >> 21) & 0x07; nkeynes@1153: if( (entry & 0x01000000) && (pvr2_scene.shadow_mode == SHADOW_FULL) ) { nkeynes@1153: it->poly_size = 5 + (vertex_length<<1) * vertex_count; nkeynes@1153: } else { nkeynes@1153: it->poly_size = 3 + vertex_length * vertex_count; nkeynes@1153: } nkeynes@1153: it->strip_count = ((entry >> 25) & 0x0F); nkeynes@1153: it->poly_addr = entry & 0x001FFFFF; nkeynes@1153: return; nkeynes@1151: } else { nkeynes@1153: /* Other polygon */ nkeynes@1153: it->strip_count = 0; nkeynes@1153: it->poly_addr = entry & 0x001FFFFF; nkeynes@1153: return; nkeynes@1145: } nkeynes@1145: } nkeynes@1145: } nkeynes@1145: nkeynes@1145: static void tileiter_init( tileiter *it, uint32_t segptr ) nkeynes@1145: { nkeynes@1145: if( IS_TILE_PTR(segptr) ) { nkeynes@1145: it->ptr = (uint32_t *)(pvr2_main_ram + (segptr & 0x007FFFFF)); nkeynes@1145: tileiter_read(it); nkeynes@1145: } else { nkeynes@1145: it->ptr = 0; nkeynes@1145: } nkeynes@1145: } nkeynes@1145: nkeynes@1145: static inline void tileiter_next( tileiter *it ) nkeynes@1145: { nkeynes@1145: assert( it->ptr != NULL ); nkeynes@1145: if( it->strip_count > 0 ) { nkeynes@1145: it->strip_count--; nkeynes@1145: it->poly_addr += it->poly_size; nkeynes@1145: } else { nkeynes@1145: it->ptr++; nkeynes@1145: tileiter_read(it); nkeynes@1145: } nkeynes@1145: } nkeynes@1145: nkeynes@1145: nkeynes@1145: /************************* tileentryiter functions **************************/ nkeynes@1145: nkeynes@1145: /** nkeynes@1145: * Read the entry pointed to by it->ptr, updating the pointer to point nkeynes@1145: * to the next real element if the current value is not a polygon entry. nkeynes@1145: */ nkeynes@1145: static void tileentryiter_read( tileentryiter *it ) nkeynes@1145: { nkeynes@1145: for(;;){ nkeynes@1145: uint32_t entry = *it->ptr; nkeynes@1145: uint32_t tag = entry >> 28; nkeynes@1145: if( tag < 0x0C ) { nkeynes@1145: if( tag & 0x08 ) { nkeynes@1145: it->strip_count = ((entry >> 25) & 0x0F); nkeynes@1145: } else { nkeynes@1145: it->strip_count = 0; nkeynes@1145: } nkeynes@1145: return; nkeynes@1145: } else { nkeynes@1145: if( tag == 0x0F ) { nkeynes@1145: it->ptr = NULL; nkeynes@1145: return; nkeynes@1145: } else if( tag == 0x0E ) { nkeynes@1145: it->ptr = (uint32_t *)(pvr2_main_ram + (entry&0x007FFFFF)); nkeynes@1145: entry = *it->ptr; nkeynes@1145: } else { nkeynes@1145: /* Illegal? Skip */ nkeynes@1145: it->ptr++; nkeynes@1145: } nkeynes@1145: } nkeynes@1145: } nkeynes@1145: } nkeynes@1145: nkeynes@1145: nkeynes@1145: static void tileentryiter_init( tileentryiter *it, uint32_t segptr ) nkeynes@1145: { nkeynes@1145: if( IS_TILE_PTR(segptr) ) { nkeynes@1145: it->ptr = (uint32_t *)(pvr2_main_ram + (segptr & 0x007FFFFF)); nkeynes@1145: tileentryiter_read(it); nkeynes@1145: } else { nkeynes@1145: it->ptr = 0; nkeynes@1145: } nkeynes@1145: } nkeynes@1145: nkeynes@1145: static void inline tileentryiter_next( tileentryiter *it ) nkeynes@1145: { nkeynes@1145: it->ptr++; nkeynes@1145: tileentryiter_read(it); nkeynes@1145: } nkeynes@1145: nkeynes@1145: nkeynes@1145: #ifdef __cplusplus nkeynes@1145: } nkeynes@1145: #endif nkeynes@1145: nkeynes@1145: #endif /* !lxdream_tileiter_H */