⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 t3dlib5.cpp

📁 3D游戏编程大师技巧第十一章的源代码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// T3DLIB5.CPP

#define STANDALONE 0

// INCLUDES ///////////////////////////////////////////////////

#define DEBUG_ON

#define WIN32_LEAN_AND_MEAN  

#if (STANDALONE==1)
#define INITGUID       // you need this or DXGUID.LIB
#endif

#include <windows.h>   // include important windows stuff
#include <windowsx.h> 
#include <mmsystem.h>
#include <objbase.h>
#include <iostream.h> // include important C/C++ stuff
#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#include <io.h>
#include <fcntl.h>
#include <direct.h>
#include <wchar.h>

#include <ddraw.h>      // needed for defs in T3DLIB1.H 
#include "T3DLIB1.H"    // T3DLIB4 is based on some defs in this 
#include "T3DLIB4.H"
#include "T3DLIB5.H"

// CLASSES ////////////////////////////////////////////////////

// PROTOTYPES /////////////////////////////////////////////////

// GLOBALS ////////////////////////////////////////////////////

#if (STANDALONE==1)
HWND main_window_handle           = NULL; // save the window handle
HINSTANCE main_instance           = NULL; // save the instance
char buffer[256];                         // used to print text
#endif

// FUNCTIONS //////////////////////////////////////////////////

char *Get_Line_PLG(char *buffer, int maxlength, FILE *fp)
{
// this little helper function simply read past comments 
// and blank lines in a PLG file and always returns full 
// lines with something on them on NULL if the file is empty

int index = 0;  // general index
int length = 0; // general length

// enter into parsing loop
while(1)
     {
     // read the next line
     if (!fgets(buffer, maxlength, fp))
     return(NULL);

    // kill the whitespace
    for (length = strlen(buffer), index = 0; isspace(buffer[index]); index++);
 
    // test if this was a blank line or a comment
    if (index >= length || buffer[index]=='#') 
       continue;
   
    // at this point we have a good line
    return(&buffer[index]);
    } // end while

} // end Get_Line_PLG

///////////////////////////////////////////////////////////////

float Compute_OBJECT4DV1_Radius(OBJECT4DV1_PTR obj)
{
// this function computes the average and maximum radius for 
// sent object and opdates the object data

// reset incase there's any residue
obj->avg_radius = 0;
obj->max_radius = 0;

// loop thru and compute radius
for (int vertex = 0; vertex < obj->num_vertices; vertex++)
    {
    // update the average and maximum radius
    float dist_to_vertex = 
          sqrt(obj->vlist_local[vertex].x*obj->vlist_local[vertex].x +
               obj->vlist_local[vertex].y*obj->vlist_local[vertex].y +
               obj->vlist_local[vertex].z*obj->vlist_local[vertex].z);
    
    // accumulate total radius
    obj->avg_radius+=dist_to_vertex;

    // update maximum radius   
    if (dist_to_vertex > obj->max_radius)
       obj->max_radius = dist_to_vertex; 
 
    } // end for vertex

// finallize average radius computation
obj->avg_radius/=obj->num_vertices;

// return max radius
return(obj->max_radius);

} // end Compute_OBJECT4DV1_Radius

///////////////////////////////////////////////////////////////

int Load_OBJECT4DV1_PLG(OBJECT4DV1_PTR obj, // pointer to object
                    char *filename,     // filename of plg file
                    VECTOR4D_PTR scale,     // initial scaling factors
                    VECTOR4D_PTR pos,       // initial position
                    VECTOR4D_PTR rot)       // initial rotations
{
// this function loads a plg object in off disk, additionally
// it allows the caller to scale, position, and rotate the object
// to save extra calls later for non-dynamic objects

FILE *fp;          // file pointer
char buffer[256];  // working buffer

char *token_string;  // pointer to actual token text, ready for parsing

// file format review, note types at end of each description
// # this is a comment

// # object descriptor
// object_name_string num_verts_int num_polys_int

// # vertex list
// x0_float y0_float z0_float
// x1_float y1_float z1_float
// x2_float y2_float z2_float
// .
// .
// xn_float yn_float zn_float
//
// # polygon list
// surface_description_ushort num_verts_int v0_index_int v1_index_int ..  vn_index_int
// .
// .
// surface_description_ushort num_verts_int v0_index_int v1_index_int ..  vn_index_int

// lets keep it simple and assume one element per line
// hence we have to find the object descriptor, read it in, then the
// vertex list and read it in, and finally the polygon list -- simple :)

// Step 1: clear out the object and initialize it a bit
memset(obj, 0, sizeof(OBJECT4DV1));

// set state of object to active and visible
obj->state = OBJECT4DV1_STATE_ACTIVE | OBJECT4DV1_STATE_VISIBLE;

// set position of object
obj->world_pos.x = pos->x;
obj->world_pos.y = pos->y;
obj->world_pos.z = pos->z;
obj->world_pos.w = pos->w;

// Step 2: open the file for reading
if (!(fp = fopen(filename, "r")))
   {
   Write_Error("Couldn't open PLG file %s.", filename);
   return(0);
   } // end if

// Step 3: get the first token string which should be the object descriptor
if (!(token_string = Get_Line_PLG(buffer, 255, fp)))
   {
   Write_Error("PLG file error with file %s (object descriptor invalid).",filename);
   return(0);
   } // end if

Write_Error("Object Descriptor: %s", token_string);

// parse out the info object
sscanf(token_string, "%s %d %d", obj->name, &obj->num_vertices, &obj->num_polys);

// Step 4: load the vertex list
for (int vertex = 0; vertex < obj->num_vertices; vertex++)
    {
    // get the next vertex
    if (!(token_string = Get_Line_PLG(buffer, 255, fp)))
          {
          Write_Error("PLG file error with file %s (vertex list invalid).",filename);
          return(0);
          } // end if

    // parse out vertex
    sscanf(token_string, "%f %f %f", &obj->vlist_local[vertex].x, 
                                     &obj->vlist_local[vertex].y, 
                                     &obj->vlist_local[vertex].z);
    obj->vlist_local[vertex].w = 1;    

    // scale vertices
    obj->vlist_local[vertex].x*=scale->x;
    obj->vlist_local[vertex].y*=scale->y;
    obj->vlist_local[vertex].z*=scale->z;

    Write_Error("\nVertex %d = %f, %f, %f, %f", vertex,
                                           obj->vlist_local[vertex].x, 
                                           obj->vlist_local[vertex].y, 
                                           obj->vlist_local[vertex].z,
                                           obj->vlist_local[vertex].w);

    } // end for vertex

// compute average and max radius
Compute_OBJECT4DV1_Radius(obj);

Write_Error("\nObject average radius = %f, max radius = %f", 
            obj->avg_radius, obj->max_radius);

int poly_surface_desc = 0; // PLG/PLX surface descriptor
int poly_num_verts    = 0; // number of vertices for current poly (always 3)
char tmp_string[8];        // temp string to hold surface descriptor in and
                           // test if it need to be converted from hex

// Step 5: load the polygon list
for (int poly=0; poly < obj->num_polys; poly++)
    {
    // get the next polygon descriptor
    if (!(token_string = Get_Line_PLG(buffer, 255, fp)))
        {
        Write_Error("PLG file error with file %s (polygon descriptor invalid).",filename);
        return(0);
        } // end if
   
    Write_Error("\nPolygon %d:", poly);

    // each vertex list MUST have 3 vertices since we made this a rule that all models
    // must be constructed of triangles
    // read in surface descriptor, number of vertices, and vertex list
    sscanf(token_string, "%s %d %d %d %d", tmp_string,
                                           &poly_num_verts, // should always be 3 
                                           &obj->plist[poly].vert[0],
                                           &obj->plist[poly].vert[1],
                                           &obj->plist[poly].vert[2]);
    

    // since we are allowing the surface descriptor to be in hex format
    // with a leading "0x" we need to test for it
    if (tmp_string[0] == '0' && toupper(tmp_string[1]) == 'X')
       sscanf(tmp_string,"%x", &poly_surface_desc);
    else
       poly_surface_desc = atoi(tmp_string);
    
    // point polygon vertex list to object's vertex list
    // note that this is redundant since the polylist is contained
    // within the object in this case and its up to the user to select
    // whether the local or transformed vertex list is used when building up
    // polygon geometry, might be a better idea to set to NULL in the context
    // of polygons that are part of an object
    obj->plist[poly].vlist = obj->vlist_local; 

    Write_Error("\nSurface Desc = 0x%.4x, num_verts = %d, vert_indices [%d, %d, %d]", 
                                                         poly_surface_desc, 
                                                         poly_num_verts, 
                                                         obj->plist[poly].vert[0],
                                                         obj->plist[poly].vert[1],
                                                         obj->plist[poly].vert[2]);

    // now we that we have the vertex list and we have entered the polygon
    // vertex index data into the polygon itself, now let's analyze the surface
    // descriptor and set the fields for the polygon based on the description

    // extract out each field of data from the surface descriptor
    // first let's get the single/double sided stuff out of the way
    if ((poly_surface_desc & PLX_2SIDED_FLAG))
       {
       SET_BIT(obj->plist[poly].attr, POLY4DV1_ATTR_2SIDED);
       Write_Error("\n2 sided.");
       } // end if
    else
       {
       // one sided
       Write_Error("\n1 sided.");
       } // end else

    // now let's set the color type and color
    if ((poly_surface_desc & PLX_COLOR_MODE_RGB_FLAG)) 
       {
       // this is an RGB 4.4.4 surface
       SET_BIT(obj->plist[poly].attr,POLY4DV1_ATTR_RGB16);
 
       // now extract color and copy into polygon color
       // field in proper 16-bit format 
       // 0x0RGB is the format, 4 bits per pixel 
       int red   = ((poly_surface_desc & 0x0f00) >> 8);
       int green = ((poly_surface_desc & 0x00f0) >> 4);
       int blue  = (poly_surface_desc & 0x000f);

       // although the data is always in 4.4.4 format, the graphics card
       // is either 5.5.5 or 5.6.5, but our virtual color system translates
       // 8.8.8 into 5.5.5 or 5.6.5 for us, but we have to first scale all
       // these 4.4.4 values into 8.8.8
       obj->plist[poly].color = RGB16Bit(red*16, green*16, blue*16);
       Write_Error("\nRGB color = [%d, %d, %d]", red, green, blue);
       } // end if
    else
       {
       // this is an 8-bit color indexed surface
       SET_BIT(obj->plist[poly].attr,POLY4DV1_ATTR_8BITCOLOR);

       // and simple extract the last 8 bits and that's the color index
       obj->plist[poly].color = (poly_surface_desc & 0x00ff);
       
       Write_Error("\n8-bit color index = %d", obj->plist[poly].color);

       } // end else

   // handle shading mode
   int shade_mode = (poly_surface_desc & PLX_SHADE_MODE_MASK);

   // set polygon shading mode
   switch(shade_mode)
         {
         case PLX_SHADE_MODE_PURE_FLAG: {
         SET_BIT(obj->plist[poly].attr, POLY4DV1_ATTR_SHADE_MODE_PURE);
         Write_Error("\nShade mode = pure");
         } break;

         case PLX_SHADE_MODE_FLAT_FLAG: {
         SET_BIT(obj->plist[poly].attr, POLY4DV1_ATTR_SHADE_MODE_FLAT);
         Write_Error("\nShade mode = flat");

         } break;

         case PLX_SHADE_MODE_GOURAUD_FLAG: {
         SET_BIT(obj->plist[poly].attr, POLY4DV1_ATTR_SHADE_MODE_GOURAUD);
         Write_Error("\nShade mode = gouraud");
         } break;

         case PLX_SHADE_MODE_PHONG_FLAG: {
         SET_BIT(obj->plist[poly].attr, POLY4DV1_ATTR_SHADE_MODE_PHONG);
         Write_Error("\nShade mode = phong");
         } break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -