From: slack Date: Mon, 13 Oct 2008 03:00:18 +0000 (+0200) Subject: Model & texture code improved (including new exporter format), new ship model+texture... X-Git-Url: http://slack.codemaniacs.com/git/?a=commitdiff_plain;h=14aebe2d3a5eb0c690ffea5377d52d8410cc3ab9;p=laz0r.git Model & texture code improved (including new exporter format), new ship model+texture, WIP new texture format and GU_PSM_5650 conversion tool --- diff --git a/README b/README new file mode 100644 index 0000000..fc7ee55 --- /dev/null +++ b/README @@ -0,0 +1,4 @@ +Ship models from: + +http://www.turbosquid.com/3d-models/3d-spaceship-ship-space-model/408426 + diff --git a/game.cc b/game.cc index 2bcfab7..9099a59 100644 --- a/game.cc +++ b/game.cc @@ -17,8 +17,8 @@ int game_main(int argc, char **argv) GFX.init(); //Model cube("colors-noUV.lob"); - Model cube("models/ship.lob"); - Texture texture("models/ship.tga"); + Model cube("models/shipdawhip.lob"); + Texture texture("models/shipdawhip.tga"); //sceKernelDcacheWritebackRange(cube.vertices, cube.num_vertices * sizeof(Vertex)); //sceKernelDcacheWritebackRange(cube.indices, cube.num_faces * sizeof(unsigned short)); //sceKernelDcacheWritebackRange(&cube, sizeof(cube)); @@ -26,10 +26,7 @@ int game_main(int argc, char **argv) GFX.perspective(75.0f, 16.0f/9.0f, 0.5f, 1000.0f); - ScePspFVector3 eye={0,0,-10}; - ScePspFVector3 center={0,0,0}; - ScePspFVector3 up={0,1,0}; - GFX.look_at(&eye, ¢er, &up); + GFX.look_at(0,0,-15, 0,0,0, 0,1,0); sceGumMatrixMode(GU_MODEL); int i=0; @@ -44,20 +41,11 @@ int game_main(int argc, char **argv) sceGumRotateY(0.001f*i); sceGumRotateZ(0.001f*i); sceGuColor(GU_COLOR(1.0f,1.0f,1.0f,0.0f)); - sceGuTexImage( 0, texture.width, texture.height, texture.width, texture.pixels ); - sceGumDrawArray(GU_TRIANGLES, - GU_TEXTURE_32BITF | GU_COLOR_8888 | GU_NORMAL_32BITF | - GU_VERTEX_32BITF | GU_TRANSFORM_3D | GU_INDEX_16BIT, cube.num_faces*3, - cube.indices, cube.vertices); + texture.bind(); + sceGumDrawArray(GU_TRIANGLES, cube.vtype | GU_TRANSFORM_3D, + cube.num_faces*3, cube.indices, cube.vertices); - ScePspFVector3 move={4,0,0}; - sceGumLoadIdentity(); - sceGumRotateZ(0.001f*i); - sceGumTranslate(&move); - - sceGuColor(GU_COLOR(1.0f,0.0f,0.0f,0.0f)); - sceGumDrawArray(GU_TRIANGLES, GU_VERTEX_32BITF | GU_TRANSFORM_3D, 3, 0, triangle); sceGuFinish(); sceGuSync(0,0); diff --git a/gfx.cc b/gfx.cc index 6268c6c..c7f1b5d 100644 --- a/gfx.cc +++ b/gfx.cc @@ -38,18 +38,17 @@ void Gfx::init() sceGuDepthFunc( GU_GEQUAL ); sceGuEnable( GU_DEPTH_TEST ); sceGuShadeModel( GU_SMOOTH ); - sceGuFrontFace( GU_CW ); - //sceGuEnable( GU_CULL_FACE ); - //sceGuEnable( GU_CLIP_PLANES ); + sceGuFrontFace( GU_CCW ); + sceGuEnable( GU_CULL_FACE ); + sceGuEnable( GU_CLIP_PLANES ); // set clear color/depth - sceGuClearColor( GU_COLOR( 1.0f, 0.0f, 1.0f, 1.0f ) ); + sceGuClearColor( GU_COLOR( 0.0f, 0.0f, 0.0f, 1.0f ) ); sceGuClearDepth(0); // setup texture sceGuEnable(GU_TEXTURE_2D); //Enable Texture2D - sceGuTexMode( GU_PSM_8888, 0, 0, 0 ); // last 0 must be 1 if swizzled - sceGuTexFunc( GU_TFX_DECAL, GU_TCC_RGB ); + sceGuTexFunc( GU_TFX_MODULATE, GU_TCC_RGB ); sceGuTexFilter( GU_LINEAR, GU_LINEAR ); // Linear filtering (Good Quality) (NEW) sceGuTexScale( 1.0f, 1.0f ); // No scaling sceGuTexOffset( 0.0f, 0.0f ); @@ -69,6 +68,7 @@ void Gfx::init() void Gfx::cleanup() { sceGuTerm(); + free(display_list); } void Gfx::update_fps( void ) @@ -79,7 +79,8 @@ void Gfx::update_fps( void ) if( ((fps_tick_now - fps_tick_last)/((float)tick_resolution)) >= 1.0f ) { fps_tick_last = fps_tick_now; - sprintf( fps_display, "ticks=%f, FPS: %d", ((double)fps_tick_now/(double)tick_resolution), frames_drawn ); + //sprintf( fps_display, "ticks=%f, FPS: %d", ((double)fps_tick_now/(double)tick_resolution), frames_drawn ); + sprintf( fps_display, "FPS: %d", frames_drawn ); frames_drawn = 0; } pspDebugScreenSetOffset( (int)fbp0 ); @@ -101,11 +102,16 @@ void Gfx::perspective(float fov, float aspect, float znear, float zfar) sceGumPerspective(fov, aspect, znear, zfar); } -void Gfx::look_at(ScePspFVector3 *eye, ScePspFVector3 *center, ScePspFVector3 *up) +void Gfx::look_at(float eye_x, float eye_y, float eye_z, + float center_x, float center_y, float center_z, + float up_x, float up_y, float up_z) { sceGumMatrixMode(GU_VIEW); sceGumLoadIdentity(); - sceGumLookAt(eye, center, up); + ScePspFVector3 eye={eye_x, eye_y, eye_z}; + ScePspFVector3 center={center_x, center_y, center_z}; + ScePspFVector3 up={up_x, up_y, up_z}; + sceGumLookAt(&eye, ¢er, &up); } diff --git a/gfx.h b/gfx.h index 83eb2d4..7ef25e5 100644 --- a/gfx.h +++ b/gfx.h @@ -27,6 +27,9 @@ class Gfx: public Singleton void perspective(float fov, float aspect, float znear, float zfar); void look_at(ScePspFVector3 *eye, ScePspFVector3 *center, ScePspFVector3 *up); + void look_at(float eye_x, float eye_y, float eye_z, + float center_x, float center_y, float center_z, + float up_x, float up_y, float up_z); }; #define GFX Gfx::Instance() diff --git a/model.cc b/model.cc index 48820f9..eefc843 100644 --- a/model.cc +++ b/model.cc @@ -1,6 +1,7 @@ #include "model.h" #include #include +#include inline bool isnan(float x) { @@ -9,18 +10,42 @@ inline bool isnan(float x) struct ModelHeader { - char sig[8]; // "laz0rOBJ" + char sig[4]; // "lzrO" + int vtype; int num_vertices; int num_faces; }; +size_t Model::vertex_size() +{ + size_t result=0; + if ((vtype & GU_TEXTURE_BITS) == GU_TEXTURE_8BIT) { printf("GU_TEXTURE_8BIT\n"); result += 2; } + else if ((vtype & GU_TEXTURE_BITS) == GU_TEXTURE_16BIT) { printf("GU_TEXTURE_16BIT\n"); result +=4; } + else if ((vtype & GU_TEXTURE_BITS) == GU_TEXTURE_32BITF) { printf("GU_TEXTURE_32BITF\n"); result += 8; } + + if ((vtype & GU_COLOR_BITS) == GU_COLOR_5650) { printf("GU_COLOR_5650\n"); result += 2; } + else if ((vtype & GU_COLOR_BITS) == GU_COLOR_5551) { printf("GU_COLOR_5551\n"); result += 2; } + else if ((vtype & GU_COLOR_BITS) == GU_COLOR_4444) { printf("GU_COLOR_4444\n"); result += 2; } + else if ((vtype & GU_COLOR_BITS) == GU_COLOR_8888) { printf("GU_COLOR_8888\n"); result += 4; } + + if ((vtype & GU_NORMAL_BITS) == GU_NORMAL_8BIT) { printf("GU_NORMAL_8BIT\n"); result += 3; } + else if ((vtype & GU_NORMAL_BITS) == GU_NORMAL_16BIT) { printf("GU_NORMAL_16BIT\n"); result += 6; } + else if ((vtype & GU_NORMAL_BITS) == GU_NORMAL_32BITF) { printf("GU_NORMAL_32BITF\n"); result += 12; } + + if ((vtype & GU_VERTEX_BITS) == GU_VERTEX_8BIT) { printf("GU_VERTEX_8BIT\n"); result += 3; } + else if ((vtype & GU_VERTEX_BITS) == GU_VERTEX_16BIT) { printf("GU_VERTEX_16BIT\n"); result += 6; } + else if ((vtype & GU_VERTEX_BITS) == GU_VERTEX_32BITF) { printf("GU_VERTEX_32BITF\n"); result += 12; } + + return result; +} + Model::Model(const char *filename) { printf("Reading model %s\n", filename); FILE *f=fopen(filename, "r"); ModelHeader h; fread(&h, sizeof(ModelHeader), 1, f); - if (strncmp(h.sig, "laz0rOBJ", 8)) + if (strncmp(h.sig, "lzrO", 4)) { printf("Error, not a model file.\n"); num_vertices=0; @@ -28,22 +53,17 @@ Model::Model(const char *filename) return; } + vtype = h.vtype; num_vertices = h.num_vertices; num_faces = h.num_faces; - vertices = new Vertex[num_vertices]; + vertices = new unsigned char[num_vertices*vertex_size()]; indices = new unsigned short[num_faces*3]; - fread(vertices, sizeof(Vertex), num_vertices, f); + fread(vertices, vertex_size(), num_vertices, f); fread(indices, sizeof(unsigned short), 3*num_faces, f); fclose(f); - for (int i=0; i - -struct Vertex -{ - float u,v; - u32 color; - float nx,ny,nz; - float x,y,z; -}; +#include struct Model { + int vtype; int num_vertices; int num_faces; - Vertex *vertices; + unsigned char *vertices; unsigned short *indices; + size_t vertex_size(); + Model(const char *filename); ~Model(); }; diff --git a/models/shipdawhip.lob b/models/shipdawhip.lob new file mode 100644 index 0000000..49975b0 Binary files /dev/null and b/models/shipdawhip.lob differ diff --git a/models/shipdawhip.tga b/models/shipdawhip.tga new file mode 100644 index 0000000..491e0a9 Binary files /dev/null and b/models/shipdawhip.tga differ diff --git a/texture.cc b/texture.cc index 11b34c9..46de12f 100644 --- a/texture.cc +++ b/texture.cc @@ -2,14 +2,88 @@ #include #include +#include +#include Texture::Texture(const char *filename) -{ - FILE *pFile = 0; - +{ + int len = strlen(filename); + if (!strcmp("tga", filename+len-3) || + !strcmp("TGA", filename+len-3)) + { + readTGA(filename); + } + else + { + readLTX(filename); + } +} + +// Returns number of bits per pixel based on texture type +unsigned int Texture::get_bpp() +{ + switch(mode) + { + case GU_PSM_5650: + case GU_PSM_5551: + case GU_PSM_4444: + return 16; + case GU_PSM_8888: + return 32; + default: + printf("Error: Unsupported texture type\n"); + } + return -1; +} + +// LTX == Laz0r TeXture ;) +struct LTXHeader +{ + char sig[4]; // "lzrT" + int mode; + int width; + int height; +}; + +// init the Texture from a LTX file +void Texture::readLTX(const char *filename) +{ + FILE *fp = fopen(filename, "rb"); + if(!fp) + { + printf("Error, couldn't open file\n"); + return; + } + + LTXHeader header; + + fread(&header, sizeof(LTXHeader), 1, fp); + if (strncmp("lzrT", header.sig, 4)) + { + printf("Error: not a LTX file\n"); + return; + } + + mode = header.mode; + width = header.width; + height = header.height; + swizzled = true; + + unsigned int size = width * height * (get_bpp()/8); + pixels = new unsigned char[size]; + + fread(pixels, sizeof(unsigned char), size, fp); + fclose(fp); + + printf("Read LTX texture %s (%ux%ux%u), size=%u\n", filename, width, height, get_bpp(), size); + +} + +// init the Texture from a TGA file +void Texture::readTGA(const char *filename) +{ // Variables to hold image info unsigned char tempColor; - unsigned char bitCount; int colorMode; long tgaSize; unsigned char unCompressHeader[12] = {0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -19,20 +93,22 @@ Texture::Texture(const char *filename) swizzled=false; // Open file - pFile = fopen( filename, "rb" ); + FILE *fp = fopen(filename, "rb"); - if( !pFile ) { - // if couldn't open, exit + if(!fp) + { + printf("Error, couldn't open file\n"); return; } // Read in BitmapHeader info into the structure - fread( &tgaHeader, 1, sizeof(tgaHeader), pFile ); + fread(&tgaHeader, sizeof(tgaHeader), 1, fp); // We only want to read uncompressed TGA's. Chech the // header if it is of an uncompressed one. - if( memcmp( unCompressHeader, tgaHeader, sizeof(unCompressHeader)) != 0 ) { - fclose( pFile ); + if(memcmp(unCompressHeader, tgaHeader, sizeof(unCompressHeader)) != 0) + { + fclose(fp); printf("Error, not an uncompressed TGA file\n"); width=0; height=0; @@ -41,32 +117,45 @@ Texture::Texture(const char *filename) } // Read Image info - fread( header, 1, sizeof(header), pFile ); + fread( header, 1, sizeof(header), fp ); // Calculate and save the Width & Height of Image width = header[1] * 256 + header[0]; height = header[3] * 256 + header[2]; - bitCount = header[4]; + unsigned int bpp = header[4]; + + if (bpp != 32) + { + printf("Error: only 32-bit uncompressed TGA is supported"); + return; + } + + mode = GU_PSM_8888; // Calculate color mode & image size - colorMode = bitCount / 8; + colorMode = bpp / 8; tgaSize = width * height * colorMode; printf("width=%hd, height=%hd, tgaSize=%ld\n", width, height, tgaSize); // Allocate memory for the image and load it pixels = new unsigned char[tgaSize]; - fread( pixels, sizeof(unsigned char), tgaSize, pFile ); + fread(pixels, sizeof(unsigned char), tgaSize, fp); // Convert from BGR to RGB format. - for(long index = 0; index < tgaSize; index += colorMode) { + for(long index = 0; index < tgaSize; index += colorMode) + { tempColor = pixels[index]; pixels[index] = pixels[index + 2]; pixels[index + 2] = tempColor; } // Close the file - fclose( pFile ); + fclose(fp); + + swizzle(); + swizzle(); + swizzle(); printf("Read TGA texture %s (%ux%u)\n", filename, width, height); @@ -78,11 +167,108 @@ Texture::~Texture() delete[] pixels; } -void swizzle() +void Texture::bind() { + sceGuTexMode(mode, 0, 0, swizzled? 1: 0); + sceGuTexImage(0, width, height, width, pixels); +} +void Texture::swizzle() +{ + unsigned int bytes_per_pixel = get_bpp()/8; + unsigned int i,j; + unsigned int rowblocks = (width * bytes_per_pixel / 16); + long size = width * height * long(bytes_per_pixel); + + unsigned char* out = new unsigned char[size]; + + for (j = 0; j < height; ++j) + { + for (i = 0; i < width*bytes_per_pixel; ++i) + { + unsigned int blockx = i / 16; + unsigned int blocky = j / 8; + + unsigned int x = (i - blockx*16); + unsigned int y = (j - blocky*8); + unsigned int block_index = blockx + ((blocky) * rowblocks); + unsigned int block_address = block_index * 16 * 8; + + out[block_address + x + y * 16] = pixels[i+j*width*bytes_per_pixel]; + } + } + memcpy(pixels, out, size ); + swizzled = !swizzled; + delete[] out; } +bool Texture::saveLTX(const char *filename, int dst_mode) +{ + // swizzling affects bytes, not pixels, so we unswizzle, convert + // the texture to the new pixel format, swizzle the new texture, + // save it and restore everything. + // + // FIXME: Swizzle != Unswizzle :( + + // Save current parameters + int src_mode = mode; + unsigned char *src_pixels = pixels; + bool src_swizzled = swizzled; + + // Undo swizzling, if any + if (src_swizzled) swizzle(); + if (mode != GU_PSM_8888) + { + printf("Error: Texture::saveLTX only supports GU_PSM_8888 as src mode\n"); + return false; + } + + mode = dst_mode; + printf("new_bpp=%u\n", get_bpp()); + pixels = new unsigned char[width * height * (get_bpp()/8)]; + + // convert pixel format + int dst_index=0; + for (int src_index=0; src_index < width*height*4; src_index+=4) + { + unsigned char r = src_pixels[src_index]; + unsigned char g = src_pixels[src_index+1]; + unsigned char b = src_pixels[src_index+2]; + unsigned char a = src_pixels[src_index+3]; + + switch(dst_mode) + { + case GU_PSM_5650: { + unsigned short val = ((r>>3) << 11) | ((g>>2) << 5) | (b>>3); + ((unsigned short *)pixels)[dst_index] = val; + dst_index++; + break; + } + default: + printf("Texture::saveLTX: Unsupported dst mode\n"); + return false; + } + + } + + // swizzle + swizzle(); + + FILE *fp=fopen(filename, "wb"); + LTXHeader header={{'l','z','r','T'}, dst_mode, width, height}; + fwrite(&header, sizeof(LTXHeader), 1, fp); + fwrite(pixels, width*height*(get_bpp()/8), 1, fp); + fclose(fp); + + delete[] pixels; + + // restore + pixels = src_pixels; + mode = src_mode; + if (src_swizzled) swizzle(); + + return true; +} diff --git a/texture.h b/texture.h index 21ef07c..9bd5f93 100644 --- a/texture.h +++ b/texture.h @@ -1,17 +1,27 @@ #if !defined(TEXTURE_H) #define TEXTURE_H +// NOTE: Only power of 2 textures are supported struct Texture { unsigned short width; unsigned short height; - unsigned char *pixels; + int mode; bool swizzled; + unsigned char *pixels; Texture(const char *filename); ~Texture(); - void swizzle(); + void bind(); + + bool saveLTX(const char *filename, int dst_mode); + + private: + void swizzle(); + unsigned int get_bpp(); + void readTGA(const char *filename); + void readLTX(const char *filename); }; #endif diff --git a/tools/blender_exporter.py b/tools/blender_exporter.py index 7f0bc2d..b5af93d 100644 --- a/tools/blender_exporter.py +++ b/tools/blender_exporter.py @@ -12,6 +12,75 @@ import Blender import bpy import struct +# vertex declarations from pspgu.h +def GU_TEXTURE_SHIFT(n): + return ((n)<<0) + +GU_TEXTURE_8BIT = GU_TEXTURE_SHIFT(1) +GU_TEXTURE_16BIT = GU_TEXTURE_SHIFT(2) +GU_TEXTURE_32BITF = GU_TEXTURE_SHIFT(3) +GU_TEXTURE_BITS = GU_TEXTURE_SHIFT(3) + +def GU_COLOR_SHIFT(n): + return ((n)<<2) + +GU_COLOR_5650 = GU_COLOR_SHIFT(4) +GU_COLOR_5551 = GU_COLOR_SHIFT(5) +GU_COLOR_4444 = GU_COLOR_SHIFT(6) +GU_COLOR_8888 = GU_COLOR_SHIFT(7) +GU_COLOR_BITS = GU_COLOR_SHIFT(7) + +def GU_NORMAL_SHIFT(n): + return ((n)<<5) + +GU_NORMAL_8BIT = GU_NORMAL_SHIFT(1) +GU_NORMAL_16BIT = GU_NORMAL_SHIFT(2) +GU_NORMAL_32BITF = GU_NORMAL_SHIFT(3) +GU_NORMAL_BITS = GU_NORMAL_SHIFT(3) + +def GU_VERTEX_SHIFT(n): + return ((n)<<7) + +GU_VERTEX_8BIT = GU_VERTEX_SHIFT(1) +GU_VERTEX_16BIT = GU_VERTEX_SHIFT(2) +GU_VERTEX_32BITF = GU_VERTEX_SHIFT(3) +GU_VERTEX_BITS = GU_VERTEX_SHIFT(3) + +def GU_WEIGHT_SHIFT(n): + return ((n)<<9) + +GU_WEIGHT_8BIT = GU_WEIGHT_SHIFT(1) +GU_WEIGHT_16BIT = GU_WEIGHT_SHIFT(2) +GU_WEIGHT_32BITF = GU_WEIGHT_SHIFT(3) +GU_WEIGHT_BITS = GU_WEIGHT_SHIFT(3) + +def GU_INDEX_SHIFT(n): + return ((n)<<11) + +GU_INDEX_8BIT = GU_INDEX_SHIFT(1) +GU_INDEX_16BIT = GU_INDEX_SHIFT(2) +GU_INDEX_BITS = GU_INDEX_SHIFT(3) + +def GU_WEIGHTS(n): + return ((((n)-1)&7)<<14) + +GU_WEIGHTS_BITS = GU_WEIGHTS(8) + +def GU_VERTICES(n): + return ((((n)-1)&7)<<18) + +GU_VERTICES_BITS = GU_VERTICES(8) + +def GU_TRANSFORM_SHIFT(n): + return ((n)<<23) + +GU_TRANSFORM_3D = GU_TRANSFORM_SHIFT(0) +GU_TRANSFORM_2D = GU_TRANSFORM_SHIFT(1) +GU_TRANSFORM_BITS = GU_TRANSFORM_SHIFT(1) + + + + def write(filename): vertex_list = [] # index --> {co=(x,y,z), no=(nx,ny,nz), uv=(u,v)} vertex_map = {} # (x,y,z) --> [index, index, ...] @@ -25,6 +94,14 @@ def write(filename): mesh = obj.getData(mesh=1) + # mesh flags + flags = GU_VERTEX_32BITF | GU_NORMAL_32BITF | GU_INDEX_16BIT + if mesh.faceUV: + flags |= GU_TEXTURE_32BITF + + if mesh.vertexColors: + flags |= GU_COLOR_8888 + # add every vertex for vert in mesh.verts: vx,vy,vz = vert.co @@ -92,16 +169,19 @@ def write(filename): # write header f = file(filename, "w") - f.write("laz0rOBJ") - f.write(struct.pack(" +#include +#include + +using namespace std; + +int main(int argc, char **argv) +{ + Texture t(argv[1]); + t.saveLTX(argv[2], GU_PSM_5650); +} + +