www.pudn.com > 3d_engine.zip > 3DSVIEW.C
/* ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ 3DSVIEW ³ ³ Panard Vision Demo ³ ³ (C) 1996,97 Olivier Brunet (bruneto@efrei.fr) ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ */ #include#include #include #include #include #include #include #include "pvision.h" #include "3dsread.h" #include "pmotion.h" #include "3dspm.h" #include "getopt.h" //-------------------------------------------------------------------------- unsigned int Resx=320,Resy=200,depth=8; PVWorld *Wor; PMotion *Anim; PVCam *Cam; RGBF Emissive={0,0,0}; RGBF Diffuse={1,1,1}; RGBF Specular={1,0,1}; RGBF Ambiant={0,0,0}; //-------------------------------------------------------------------------- SV_devCtx *DC; SV_modeInfo mi; char DoubleBuffering=TRUE; char VblWait=TRUE; unsigned RenderMode=PVM_PALETIZED8; unsigned TV=FALSE; unsigned ANIMATION=FALSE; float ANIMSPEED=0.5; char MatFile[255]="material.def"; //-------------------------------------------------------------------------- extern char MyKey(); #pragma aux MyKey=\ "in al,60h"\ modify[al]\ value[al]; /***********************************************************************/ short VBE_GetModeNumber(ushort *modeList,unsigned xres,unsigned yres, unsigned depth) { ushort *modes; SV_modeInfo mi; for (modes = modeList; *modes != 0xFFFF; modes++) { if (!SV_getModeInfo(*modes,&mi)) continue; if (mi.BitsPerPixel != depth || mi.XResolution != xres || mi.YResolution != yres) continue; return mi.Mode; } return -1; } void VBE_DisplayModes(ushort *modeList,ushort x,ushort y,ushort d) { ushort *modes; SV_modeInfo mi; char tmp[255]; for (modes = modeList; *modes != 0xFFFF; modes++) { if (!SV_getModeInfo(*modes,&mi)) continue; if(x!=0) if (mi.XResolution!=x) continue; if(y!=0) if (mi.YResolution!=y) continue; if(d!=0) if (mi.BitsPerPixel!=d) continue; SV_getModeName(tmp,&mi,mi.Mode,TRUE); printf("%s\n",tmp); } } /***********************************************************************/ void PVAPI UserCleanUp(unsigned t) { SV_restoreMode(); } void fatal(char *s) { PV_UserCleanUp(0); printf("\n\nFATAL! : %s\n",s); exit(1); } /***********************************************************************/ // JPEG #include #include "jpeglib.h" struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ }; typedef struct my_error_mgr * my_error_ptr; void my_error_exit (j_common_ptr cinfo) { my_error_ptr myerr = (my_error_ptr) cinfo->err; (*cinfo->err->output_message) (cinfo); longjmp(myerr->setjmp_buffer, 1); } int LoadJpeg (char * filename,PVMaterial *m) { struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; FILE * infile; /* source file */ void **buffer; char *buffer2; int row_stride; /* physical row width in output buffer */ unsigned i; printf("Loading %s for %s...\n", filename, m->Name); if ((infile = fopen(filename, "rb")) == NULL) { fprintf(stderr, "can't open %s\n", filename); return 0; } cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); fclose(infile); return 0; } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, infile); (void) jpeg_read_header(&cinfo, TRUE); cinfo.out_color_space=JCS_RGB; (void) jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components; buffer=malloc(cinfo.output_height*sizeof(void*)); if(buffer==NULL) fatal("Not enough memory to load jpeg image.\n"); buffer2=malloc(row_stride*cinfo.output_height); if(buffer2==NULL) fatal("Not enough memory to load jpeg image.\n"); for(i=0;i Name); if ((t=(UPVD8*)malloc(n))==NULL) { printf("Not Enough memory to load %s\n",na); fclose(f); return; } fread(t,1,n,f); fclose(f); pal=(RGB*)malloc(sizeof(RGB)*256); memcpy(pal,&t[256*256],256*sizeof(RGB)); PV_SetMaterialTexture(mat,256,256,t,pal); } void LoadBump(char *na,PVMaterial *mat) { UPVD8 *t; FILE *f; unsigned n; if ((f=fopen(na,"rb"))==NULL) return; printf("Loading %s for %s's bump map...\n",na,mat->Name); n=filesize(f); if ((t=(UPVD8*)malloc(n))==NULL) fatal("Not Enough memory to load bump map"); fread(t,n,1,f); fclose(f); if(PV_BuildBumpMap(mat,t,256,256,1)!=COOL) fatal("Bump SUUUUUUUXXX");; free(t); } char *ReadLine(FILE *f) { static char b[2048]; unsigned i=0; do { fscanf(f,"%s",b); } while(b[0]=='#'); while(b[i]!=0) {if(b[i]=='$') b[i]=' ';i++;} return b; } int DecodeFlags(char *a2) { int flags=0; if(a2!=NULL) { a2=strupr(a2); if(strcmp("FLAT",a2)==0) flags|=FLAT; if(strcmp("NOTHING",a2)==0) flags|=NOTHING; if(strcmp("GOURAUD",a2)==0) flags|=GOURAUD; if(strcmp("PHONG",a2)==0) flags|=PHONG; if(strcmp("BUMP",a2)==0) flags|=BUMP; if(strcmp("MAPPING",a2)==0) flags|=MAPPING; if(strcmp("AMBIANT_MAPPING",a2)==0) flags|=AMBIANT_MAPPING; if(strcmp("PERSPECTIVE_MAPPING",a2)==0) flags|=PERSPECTIVE_MAPPING; if(strcmp("AUTOMATIC",a2)==0) flags|=AUTOMATIC; if(strcmp("TEXTURE_NONE",a2)==0) flags|=TEXTURE_NONE; if(strcmp("TEXTURE_PALETIZED8",a2)==0) flags|=TEXTURE_PALETIZED8; if(strcmp("TEXTURE_RGB",a2)==0) flags|=TEXTURE_RGB; if(strcmp("TEXTURE_MIPMAP",a2)==0) flags|=TEXTURE_MIPMAP; } return flags; } void LoadMaterialsDefinitions(char *s) { FILE *f; char *l,*a1,*a2; RGBF col,col2,col3,col0; unsigned i,flags1,flags2; PVMaterial *mat; if ((f=fopen(s,"rt"))==NULL) return; printf("Reading %s\n",s); while(!feof(f)) { l=ReadLine(f); if(strcmp(l,"END")==0) break; if(strcmp(l,"SPEED")==0) { l=ReadLine(f); sscanf(l,"%f",&ANIMSPEED); } if(strcmp(l,"AMBIANT")==0) { l=ReadLine(f); sscanf(l,"%f",&col.r); l=ReadLine(f); sscanf(l,"%f",&col.g); l=ReadLine(f); sscanf(l,"%f",&col.b); printf("Setting ambiant light to (%f,%f,%f)\n",col.r,col.g,col.b); PV_WorldSetAmbiantLight(Wor,col); } if(strcmp(l,"MATERIAL")==0) { l=ReadLine(f); a1=strdup(l); l=ReadLine(f); a2=strtok(l,"|"); flags1=DecodeFlags(a2); while((a2=strtok(NULL,"|"))!=NULL) { flags1|=DecodeFlags(a2); } l=ReadLine(f); sscanf(l,"%f",&col0.r); l=ReadLine(f); sscanf(l,"%f",&col0.g); l=ReadLine(f); sscanf(l,"%f",&col0.b); l=ReadLine(f); sscanf(l,"%f",&col.r); l=ReadLine(f); sscanf(l,"%f",&col.g); l=ReadLine(f); sscanf(l,"%f",&col.b); l=ReadLine(f); sscanf(l,"%f",&col2.r); l=ReadLine(f); sscanf(l,"%f",&col2.g); l=ReadLine(f); sscanf(l,"%f",&col2.b); l=ReadLine(f); sscanf(l,"%f",&col3.r); l=ReadLine(f); sscanf(l,"%f",&col3.g); l=ReadLine(f); sscanf(l,"%f",&col3.b); l=ReadLine(f); sscanf(l,"%u",&i); l=ReadLine(f); a2=strtok(l,"|"); flags2=DecodeFlags(a2); while((a2=strtok(NULL,"|"))!=NULL) { flags2|=DecodeFlags(a2); } l=ReadLine(f); mat=PV_CreateMaterial(a1,flags1,flags2,0); if(mat==NULL) fatal("Not enough memory for materials"); PV_AddMaterial(Wor,mat); PV_SetMaterialLightInfo(mat,col,col2,col3,i); PV_SetMaterialColor(mat,col0.r,col0.g,col0.b); if(strstr(l,".jpg")!=NULL) LoadJpeg(l,mat); else LoadRaw(l, mat); l=ReadLine(f); LoadBump(l,mat); } } fclose(f); } /***********************************************************************/ void help() { printf("\n\t3DSVIEW [file1.3DS] [file2.3ds] [filex.3ds] [options]\n"); printf("\tex: 3DSVIEW -a zob.3ds -x640 zumbala.3ds -y480 -d -fplouf.def\n"); printf("Options:\n"); printf("\t -v disable VBL synch\n"); printf("\t -d disable double buffering\n"); printf("\t -l list all availlable video modes\n"); printf("\t -xNNN where NNN is the horizontal resolution\n"); printf("\t -yNNN where NNN is the vertical resolution\n"); printf("\t -r use fake 16bits render mode.\n"); printf("\t -znn use RGB (nn bits) render mode (currently 15,16,24,32).\n"); printf("\t -t TV mode.\n"); printf("\t -a Use animation info from .3ds. (MUST be first on the command line)\n"); printf("\t -ffile Use file for material definitions.\n"); } char optionStr[] = "vdlhx:y:rtz:af:"; void parseArguments(int argc,char *argv[]) /**************************************************************************** * * Function: parseArguments * Parameters: argc - Number of command line arguments * argv - Array of command line arguments * * Description: Parses the command line and forces detection of specific * SuperVGA's if specified. * ****************************************************************************/ { int i,option; char *argument; /* Parse command line options */ i = i; do { option = getopt(argc,argv,optionStr,&argument); switch (option) { case 'v': VblWait=FALSE; break; case 'd': DoubleBuffering=FALSE; break; case 'l': printf("List of available video modes on your machine:\nWARNING: All modes are not supported.\n\n"); printf("8 bits modes :\n"); VBE_DisplayModes(DC->modeList,0,0,8); getch(); printf("\n16 bits modes :\n"); VBE_DisplayModes(DC->modeList,0,0,16); getch(); printf("\n24 bits modes :\n"); VBE_DisplayModes(DC->modeList,0,0,24); getch(); printf("\n32 bits modes :\n"); VBE_DisplayModes(DC->modeList,0,0,32); exit(0); break; case 'x':Resx=atoi(argument);break; case 'y':Resy=atoi(argument);break; case 'r':RenderMode=PVM_RGB16;depth=16;break; case 'z':RenderMode=PVM_RGB; if(!strcmp(argument,"15")) depth=15; if(!strcmp(argument,"16")) depth=16; if(!strcmp(argument,"24")) depth=24; if(!strcmp(argument,"32")) depth=32; break; case 't':TV=TRUE;break; case 'a':ANIMATION=TRUE;break; case 'f':strcpy(MatFile,argument);break; case ALLDONE: break; case PARAMETER: printf("Loading %s...\n",argv[nextargv]); if (LoadMeshFrom3DS(argv[nextargv],Wor)!=COOL) fatal("Unable to load mesh file."); if(ANIMATION==TRUE) { printf("Loading animation info...\n"); if(LoadAnimFrom3DS(argv[nextargv],Anim,Wor)!=COOL) fatal("Error reading animation file."); } argv++; break; case 'h': case INVALID: default: help(); exit(1); } } while (option != ALLDONE); } /***********************************************************************/ void main(int argc,char *argv[]) { char *Screen; char Done,ch; PVMesh *o; PVLight *Light2,*Light1; char change; unsigned i; int page=1; unsigned CumulTime=0,NbTimes=0; SV_palette cpal[256]; printf("Panard-Vision Demo Program V1.51 (C) 1997, SMKaribou/GMF (bruneto@efrei.fr)\n"); printf("-h for help.\n\n"); printf("Keys : N=Normal Mode, ,=MipMapping, J=Front2Back, F&G=Change field of view.\n"); printf("þ Compiled on %s at %s.\n",__DATE__,__TIME__); printf("þ PMLib (Version %s) compiled on %s at %s.\n",PMOTION_VERSION,PMOTION_DATE,PMOTION_TIME); DC = SV_init(FALSE); /*if (!DC || DC->VBEVersion < 0x200) { printf("This program requires a VESA VBE 2.0 or higher compatible SuperVGA. Try\n"); printf("installing the Universal VESA VBE for your video card, or contact your\n"); printf("video card vendor and ask for a suitable TSR\n"); exit(1); } */ /* PVision Init */ InitPVision(); PV_UserCleanUp=UserCleanUp; if((Wor=PV_CreateWorld())==NULL) fatal("Not enough memory for PVWorld."); if((Anim=PM_CreateTree())==NULL) fatal("Not enough memory to create root node for animation.\n"); if((Cam=PV_CreateCam("CAMERA"))==NULL)fatal("Not enough memory to create camera.\n"); // Need to create and assign a cam before calling LoadAnimFrom3DS() PV_SetCamFieldOfView(Cam,1.5); Cam->Height=Resy; Cam->Width=Resx; PV_AssignCam(Cam); // Analyze command line if (argc<2) { help(); exit(1); } parseArguments(argc,argv); // SVGA if(VBE_GetModeNumber(DC->modeList,Resx,Resy,depth)==-1) fatal("Unsupported video mode (try -l option).\n"); SV_getModeInfo(VBE_GetModeNumber(DC->modeList,Resx,Resy,depth),&mi); if((mi.Attributes&svHaveMultiBuffer)==0) DoubleBuffering=FALSE; if(((mi.Attributes&svHaveLinearBuffer)==0)&&(DC->haveVirtualBuffer==FALSE)) fatal("Sorry, banked modes not supported.\n"); printf("Rendering in %ux%ux%uc\n\t þ %s\n\t þ %s\n\t þ %s\n",Resx,Resy,depth==32?(1<<24):(1< ReservedColors=0; LoadMaterialsDefinitions(MatFile); printf("Thinking....\n"); // Go ! Panard Vision PV_SetMode(RenderMode); if(!(PV_Mode&PVM_PALETIZED8)) if(PV_SetRGBIndexingMode(mi.RedMaskSize,mi.GreenMaskSize,mi.BlueMaskSize, mi.RedFieldPosition,mi.GreenFieldPosition,mi.BlueFieldPosition,mi.RsvdMaskSize)!=COOL) fatal("RGB Setup : Internal Error\n"); // The order of the 3 next operations does matter if(PV_CompileMeshes(Wor)!=COOL) fatal("Error during material compilation."); if(PV_CompileMaterials(Wor,NULL,NULL)!=COOL) fatal("Not enough memory for light transcoding maps.\n");; if(Wor->Global256Palette!=NULL) for(i=0;i ReservedColors;i++) { Wor->Global256Palette[i].r=i*63/(Wor->ReservedColors-1); Wor->Global256Palette[i].g=i*63/(Wor->ReservedColors-1); Wor->Global256Palette[i].b=i*63/(Wor->ReservedColors-1); } // Stats o=Wor->Objs; while(o!=NULL) { printf("\tþ %s (%lu vertexes, %lu faces, %lu boxes), %s\n",o->Name,o->NbrVertexes,o->NbrFaces,o->NbrBoxes,o->Face[0].Material); o=o->Next; } printf("World : %lu vertexes, %lu faces\n",Wor->NbrVertexes,Wor->NbrFaces); printf("%lu objects in the World.\n",Wor->NbrObjs); getch(); // SVGA Kit if(!SV_setMode(VBE_GetModeNumber(DC->modeList,Resx,Resy,depth)|svLinearBuffer,FALSE,FALSE,2)) if(!SV_setMode(VBE_GetModeNumber(DC->modeList,Resx,Resy,depth),FALSE,TRUE,2)) fatal("Unable to set up video mode, unable to obtain a frame buffer hardware or software.\n"); if(PV_Mode&PVM_PALETIZED8) { for(i=0;i<256;i++) { cpal[i].red=Wor->Global256Palette[i].r*4; cpal[i].green=Wor->Global256Palette[i].g*4; cpal[i].blue=Wor->Global256Palette[i].b*4; cpal[i].alpha=0; } SV_setPalette(0,256,cpal,-1); } if(DoubleBuffering==TRUE) SV_setActivePage(1); /* Setting up Clipping infos */ if(TV==FALSE) {if (PV_SetClipLimit(0,Resx-1,0,Resy-1,mi.BytesPerScanLine,Resx/2,Resy/2)!=COOL) fatal("Not enough memory for S-Buffer.\n");} else if (PV_SetClipLimit(0,Resx-1,0,Resy/2,mi.BytesPerScanLine*2,Resx/2,Resy/4)!=COOL) fatal("Not enough memory for S-Buffer.\n"); // Camera&Light stuff Light2=PV_CreateLight(PVL_INFINITEPOINT,""); PV_SetLightIntensity(Light2,1); PV_SetLightDirection(Light2,0,1,0); PV_AddLight(Wor,Light2); Light2=PV_CreateLight(PVL_DIRECTIONAL,""); PV_SetLightIntensity(Light2,1); PV_SetLightDirection(Light2,0,1,0); Light1=PV_CreateLight(PVL_DIRECTIONAL,""); PV_SetLightIntensity(Light1,1); PV_SetLightDirection(Light1,0,0,-1); Light1->Color.g=0.2; Light1->Color.b=0; Light2->Color.r=0.1; Light2->Color.b=0.8; PV_AddLight(Wor,Light1); PV_AddLight(Wor,Light2); Done=0; ZTimerInit(); do { if(ANIMATION==TRUE){ PM_SetCurrentTime(Anim,Anim->CurrentTime+ANIMSPEED); PM_ComputeCurrentTime(Anim); } if(DoubleBuffering==TRUE) { Screen=(char*)DC->originOffset; SV_clear(0); } else memset(Screen,0,mi.BytesPerScanLine*Resy); PV_ComputeWorld(Wor); SV_beginDirectAccess(); LZTimerOn(); PV_RenderWorld(Wor,(UPVD8*)Screen); LZTimerOff(); SV_endDirectAccess(); CumulTime+=LZTimerCount(); NbTimes++; if((change==1)||(ANIMATION==TRUE)) if(DoubleBuffering==FALSE) { memcpy((void*)DC->originOffset,Screen,mi.BytesPerScanLine*Resy); } else { SV_setVisualPage(page,VblWait); page=1-page; SV_setActivePage(page); } if(ANIMATION==FALSE) while(!kbhit()); ch=MyKey(); while(kbhit()) getch(); change=1; switch (ch) { // + case 13:PV_ScaleWorld(Wor,1.1,1.1,1.1);break; // - case 12:PV_ScaleWorld(Wor,0.9,0.9,0.9);break; // 4 case 75:PV_SetCamPos(Cam,Cam->pos.xf-1,Cam->pos.yf,Cam->pos.zf); break; // 6 case 77:PV_SetCamPos(Cam,Cam->pos.xf+1,Cam->pos.yf,Cam->pos.zf); break; // 2 case 80:PV_SetCamPos(Cam,Cam->pos.xf,Cam->pos.yf+1,Cam->pos.zf); break; // 8 case 72:PV_SetCamPos(Cam,Cam->pos.xf,Cam->pos.yf-1,Cam->pos.zf); break; // 7 case 71:PV_CamAhead(Cam,-1);break; // 1 case 79:PV_CamAhead(Cam,1);break; // A case 30: PV_SetCamAngles(Cam,Cam->yaw,Cam->pitch-0.1,Cam->roll); break; // Q case 16:PV_SetCamAngles(Cam,Cam->yaw,Cam->pitch+0.1,Cam->roll); break; // O case 24:PV_SetCamAngles(Cam,Cam->yaw-0.1,Cam->pitch,Cam->roll); break; // P case 25:PV_SetCamAngles(Cam,Cam->yaw+0.1,Cam->pitch,Cam->roll); break; // Z case 44:PV_SetCamAngles(Cam,Cam->yaw,Cam->pitch,Cam->roll-0.1); break; // S case 31:PV_SetCamAngles(Cam,Cam->yaw,Cam->pitch,Cam->roll+0.1); break; // N case 49:PV_SetMode(RenderMode); break; // M case 50:PV_SetMode(PV_Mode|PVM_MIPMAPPING); break; // X case 45:PV_SetLightDirection(Light1,Light1->Direction.xf+0.1,Light1->Direction.yf,Light1->Direction.zf);break; // C case 46:PV_SetLightDirection(Light1,Light1->Direction.xf-0.1,Light1->Direction.yf,Light1->Direction.zf);break; // V case 47:PV_SetLightPosition(Light1,Light1->Position.xf+10,Light1->Position.yf,Light1->Position.zf);break; // B case 48:PV_SetLightPosition(Light1,Light1->Position.xf-10,Light1->Position.yf,Light1->Position.zf);break; // J case 36:PV_SetMode(PV_Mode|PVM_SBUFFER); break; // F case 33: PV_SetCamFieldOfView(Cam,Cam->fieldofview+0.1);break; // G case 34: PV_SetCamFieldOfView(Cam,Cam->fieldofview-0.1);break; // D case 32: Wor->AmbiantLight.b+=0.05;break; // E case 18: Wor->AmbiantLight.b-=0.05;break; // ESC case 1:Done=1; default:change=0; } } while(Done==0); if(DoubleBuffering==FALSE) free(Screen); PV_UserCleanUp(0); PV_GarbageCollector(Wor); PV_KillWorld(Wor); printf("\n\nSpeed stat: %d frames rendered, %f æs/frame\n",NbTimes,(float)CumulTime/(float)NbTimes); printf("\n\n(C) 1997, SMKaribou"); }