MULTIMEDIA

Game Programming with DirectX : 3D Models - Files in C++

5/19/2013 7:11:45 PM

1. Overview of 3D Models

Some games have their own file formats that are used for storing 3D information. This allows the developers to create a format that has all of the information needed by a particular gaming application. What this information is may vary from game to game, so it really depends on the application.

For example, if you have models in your game that require the position, texture coordinates, normals, and material information, you can create a file format that suits your needs by specifying this information. The game can then load this data and render the geometry with its material in real time.

Tools Used for Creating 3D Geometry

Another option is to utilize an already existing file format. This is convenient because any tools available on the market that save information to the format of your choice can be used to create game assets. If you use an existing file format, it might not suit your needs, or it might specify more information than you need for your assets. This is often the case with formats saved by general-purpose tools, where a lot of information can appear in the file that you would not need in an actual game. Some of the most popular applications used to create 3D geometry include the following.

  • 3D Studio Max

  • Lightwave

  • XSI

  • Maya

  • ZBrush

  • Truespace

Along with using existing tools and formats, you can also write your own file exporters and converters to change a file to a format that your game is ready to use. This is a very common practice in video games, as it allows developers to use powerful and complex tools such as 3D Studio Max and save the content created in a format the game is able to read and use.

2. Files in C++

In this section we will briefly review how C++ loads file data. C++ uses the standard ifstream and ofstream classes. The ifstream class represents an input file stream, and ofstream represents an output file stream. Both classes derive from the base class, ifstream, and are part of the C++ standard.

Input and Output Streams

The data is loaded into the demo and displayed within the function LoadFileData(). This function creates an ifstream object, opens the file, checks if the file actually opened, determines the size of the file, and then reads the file’s data into memory. Once loaded, the text that was loaded from the file is displayed, the allocated memory that was used to store the file’s data is deleted, and the function returns.

To open a file using ifstream or ofstream, you call the open() function. This function takes as parameters the file name and the file mode. The file mode can be one of the following flags:

  • app: This flag tells the stream object to open a file and append new information to it.

  • ate: This flag sets the file pointer to the end of the file stream upon opening it.

  • binary: This flag indicates that the file being opened is considered a binary file and not a text file.

  • in: This flag is used to specify that the file is being used for reading rather than writing.

  • out: This flag specifies that the file is being used for writing rather than reading.

  • trunc: This flag discards data upon opening.

To check if the file successfully opened, you can use the function is_open(), which returns true if the file stream is open or false if it is not.

In the Files demo the next step calculates the file size. This can be done by setting the file pointer to the end of the file stream by calling the function seekg(), calling tellg() to get the number of bytes at that position, and then calling seekg() again to return us to the beginning of the file stream so that we are ready to read the information from the beginning. The seekg() function takes as parameters the file position to set, an offset from that position to set, and a seeking direction. In this demo we are using one of the overloaded versions that accepts an offset and a seek direction. The seek direction can be either beg, which stands for the beginning of the stream, end, which is the end of the stream, or cur, which is the current position in the stream. The function tellg() gets the file position, which can be used to represent the byte position at the current location. So if we seek to the end of the file, a call to tellg() will tell us the total bytes in the file. We seek back to the start so we can begin reading since reading occurs where the file pointer is located.

With the size of the file, we can allocate a buffer to hold that information, and then we can read it with a call to read(). The read() function takes as parameters a pointer to a buffer to read the data into and the amount you want to read. To read the entire file we use the file’s size from the beginning of the stream in this demo. Once the information is read, the file is closed, the allocated memory is deleted, and the function returns.

Other functions that are part of the ifstream class include the following that are inherited from the istream class.

  • gcount(): This function returns the number of characters extracted by the last input operation.

  • get(): This function is used to read unformatted data from the input file stream.

  • getline(): This function is used to read data from the input stream into an array.

  • ignore(): This function is used to read data from the stream and then discard it.

  • peek(): This function returns the next character in the stream but does not extract it (i.e., doesn’t move the file pointer).

  • readsome(): This function reads data up to the size of the array even if the end of the file or the number of bytes to read has yet to be reached.

  • putback(): This function decrements the file pointer back one and makes the character passed to its parameter the next character to be read from the stream.

  • unget(): This function decrements the file pointer back one.

  • sync(): This function synchronizes the input buffer with a source of characters.

  • sentry(): This function performs exception-safe prefix and suffix operations on the stream.

The ofstream class has many of the same functions minus the ones dealing with input. The ofstream class also has a function called write() that is used to write data to a file. The write() function takes as parameters the buffer to write and the amount of bytes to write. The ofstream class also has a function called flush(), which is used to force the object to write out all unwritten data as soon as possible.

The main.cpp source file for the Files demo is shown in Listing 1. The demo’s main() function saves data to a file by calling the demo’s SaveFileData() function, and then it reads it back by calling the demo’s LoadFileData() function. The data that has been read is displayed inside LoadFileData().

Listing 1. The main.cpp Source File for the Files Demo
/*
   Files in C++
   Ultimate Game Programming with DirectX 2nd Edition
   Created by Allen Sherrod
*/

#include<iostream>
#include<fstream>

using namespace std;


bool LoadFileData()
{
   ifstream fileStream;
   int fileSize = 0;

   // Open file then test that it actually opened.
   fileStream.open("test.txt", ifstream::in);

   if(fileStream.is_open() == false)
      return false;
   // Get file size.
   fileStream.seekg(0, ios::end);
   fileSize = fileStream.tellg();
   fileStream.seekg(0, ios::beg);

   if(fileSize <= 0)
      return false;

   // Allocate memory for text data.
   char *buffer = new char[fileSize];
   memset(buffer, 0, fileSize);

   if(buffer == NULL)
      return false;

   // Read data and close the file.
   fileStream.read(buffer, fileSize);
   fileStream.close();

   buffer[fileSize - 1] = '\0';

   // Display the data.
   cout << "test.txt (" << fileSize << " bytes) contents:" << endl;
   cout << buffer << endl;

   delete[] buffer;

   return true;
}

bool SaveFileData()
{
   ofstream fileStream;

   // Open file then test that it actually opened.
   fileStream.open("test.txt", ofstream::out);
   if(fileStream.is_open() == false)
      return false;

   char buffer[] = { "This is saved out to the file!" };

   // Write information to the file then close the file.
   fileStream.write(buffer, sizeof(buffer));
   fileStream.close();

   return true;
}

int main(int args, char *argc[])
{
   cout << "Loading files example in C++." << endl << endl;

   // Try to save the file.
   if(!SaveFileData())
   {
      cout << "Could not save file!" << endl << endl;
   }

   // Try to load the file.
   if(!LoadFileData())
   {
      cout << "Could not read file!" << endl << endl;
   }

   cout << "Press enter to quit." << endl;
   char c;
   cin >> c;

   return 1;
}

					  

Binary Files and Byte Ordering

Loading text files consists of loading data in a stream of characters, where a character is a single byte. This assumes the file has ASCII text, which essentially means there are no values that take up more than a byte of space. Binary files, on the other hand, or any file that assumes more than one byte per value, can have multibyte values saved to the file. Therefore, if an integer variable is 4 bytes in C++, you can save the entire variable to a file. To read it you would read the 4 bytes that make up the integer.

The problem with multibyte values is in their byte ordering. Different hardware works on different byte ordering. For example, big endian is the byte ordering used by PowerPC processors, while little endian is used by processors. When saving information to a file, the byte ordering from one piece of hardware is not translated automatically to another. This means that if you try to load a value that is in big endian on a little endian machine, the value will not be what you expect.

The solution to this problem is fairly straightforward. To start, you have to be aware of what byte ordering the machine uses and what order the file was saved in. If the two orders are different, you can simply swap the bytes that make up the variable when you read it. This can be done by simply casting the variable to a character pointer and swapping the bytes using array indexes just like you would if you had an array of four characters. When swapping, the fourth byte becomes the first, the third becomes the second, the second becomes the third, and the first byte becomes the last.

Other  
 
Video
Video tutorials
- How To Install Windows 8

- How To Install Windows Server 2012

- How To Install Windows Server 2012 On VirtualBox

- How To Disable Windows 8 Metro UI

- How To Change Account Picture In Windows 8

- How To Unlock Administrator Account in Windows 8

- How To Restart, Log Off And Shutdown Windows 8

- How To Login To Skype Using A Microsoft Account

- How To Enable Aero Glass Effect In Windows 8

- How To Install Windows Store Apps From Windows 8 Classic Desktop

- How To Disable Windows Update in Windows 8

- How To Disable Windows 8 Metro UI

- How To Add Widgets To Windows 8 Lock Screen

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010
programming4us programming4us
Top 10
Free Mobile And Desktop Apps For Accessing Restricted Websites
MASERATI QUATTROPORTE; DIESEL : Lure of Italian limos
TOYOTA CAMRY 2; 2.5 : Camry now more comely
KIA SORENTO 2.2CRDi : Fuel-sipping slugger
How To Setup, Password Protect & Encrypt Wireless Internet Connection
Emulate And Run iPad Apps On Windows, Mac OS X & Linux With iPadian
Backup & Restore Game Progress From Any Game With SaveGameProgress
Generate A Facebook Timeline Cover Using A Free App
New App for Women ‘Remix’ Offers Fashion Advice & Style Tips
SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th
Popular Tags
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Exchange Server Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe Photoshop CorelDRAW X5 CorelDraw 10 windows Phone 7 windows Phone 8 Iphone