Comparing two identical jpg files with different compression ratios - delphi

There is a directory with jpg files and one jpg file that should be compared with the files in the directory and in this way find 2 graphically identical files. It's about the simplest way. Maybe it is possible to compare the differences in R, G, B (variability), and not the R, G, B values themselves, since they may differ slightly with different degrees of jpeg compression.

for comparing 2 images:
Load the two jpgs into memory located bitmaps
see opening image file on c++ , PNG , JPEG for simple C++ Builder example just port to pascal the class names and usage should be the same in Delphi.
Compute abs differences
use Graphics::TBitmap::ScanLine[y] for fast pixel access, union or BYTE pointed for individual color channel access and compute abs average difference and max abs difference individually for each color channel.
for more info see TBitmap and ScanLine[y] usage and color channel access example
However as SilverWarior pointed out using RGB space is nto good for this so compare in luminance (just convert the RGB to luminance)
Threshold the result
simply if any of max and avg differences is bigger than some threshold the two images are not identical.
To create a list of files either use winapi FindFirst,FindNext,FindClose to obtain the directory list or use the file list from win3.11 VCL components set its directory and obtain the files in form of list...
And then just auto compare the images ...
Here small C++ builder example for comparing 2 images:
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#include <jpeg.hpp>
#pragma hdrstop
#include "win_main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TMain *Main;
Graphics::TBitmap *bmp0,*bmp1;
//---------------------------------------------------------------------------
int picture_load(Graphics::TBitmap *bmp,AnsiString name)
{
if (bmp==NULL) return 0;
if (!FileExists(name)) return 0;
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
AnsiString ext=ExtractFileExt(name).LowerCase();
for(;;)
{
if (ext==".bmp")
{
bmp->LoadFromFile(name);
break;
}
if (ext==".jpg")
{
TJPEGImage *jpg=new TJPEGImage;
if (jpg==NULL) return 0;
jpg->LoadFromFile(name);
bmp->Assign(jpg);
delete jpg;
break;
}
return 0;
}
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
return 1;
}
//---------------------------------------------------------------------------
int picture_compare(Graphics::TBitmap *bmp0,Graphics::TBitmap *bmp1)
{
if ((bmp0==NULL)&&(bmp1==NULL)) return 1;
if (bmp0==NULL) return 0;
if (bmp1==NULL) return 0;
if (bmp0->Width !=bmp1->Width ) return 0;
if (bmp0->Height!=bmp1->Height) return 0;
int x,y,a;
double c0,c1,dc,de,maxdif=0.0,avgdif=0.0;
BYTE *p0,*p1;
for (y=0;y<bmp0->Height;y++)
{
p0=(BYTE*)bmp0->ScanLine[y];
p1=(BYTE*)bmp1->ScanLine[y];
for (a=0,x=0;x<bmp0->Width;x++)
{
c0 =p0[a]; c1 =p1[a]; a++; c0*=0.0722; c1*=0.0722; // B
c0+=p0[a]; c1+=p1[a]; a++; c0*=0.7152; c1*=0.7152; // G
c0+=p0[a]; c1+=p1[a]; a++; c0*=0.2126; c1*=0.2126; // R
a++; // A
dc=fabs(c0-c1);if (maxdif<dc) maxdif=dc; avgdif+=dc;
}
}
avgdif/=bmp0->Width;
avgdif/=bmp0->Height;
if (avgdif>10) return 0;
if (maxdif>50) return 0;
return 1;
}
//---------------------------------------------------------------------------
__fastcall TMain::TMain(TComponent* Owner) : TForm(Owner)
{
bmp0=new Graphics::TBitmap;
bmp1=new Graphics::TBitmap;
picture_load(bmp0,"in0.jpg");
picture_load(bmp1,"in1.jpg");
Caption=picture_compare(bmp0,bmp1);
int xs,ys;
xs=bmp0->Width+bmp1->Width;
ys=bmp0->Height;
if (ys<bmp1->Height) ys=bmp1->Height;
ClientWidth=xs;
ClientHeight=ys;
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormDestroy(TObject *Sender)
{
if (bmp0) delete bmp0; bmp0=NULL;
if (bmp1) delete bmp1; bmp1=NULL;
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormPaint(TObject *Sender)
{
Canvas->Draw(0,0,bmp0);
Canvas->Draw(bmp0->Width,0,bmp1);
}
//---------------------------------------------------------------------------
You should play with the thresholds (I chose form very small input sample) to meet your needs and also beware this is comparing as grayscale images so you should add also some color comparison too (integrate some areas into avg color and compare that)
The function picture_compare returns true for "identical" images... beware it expects pf32bit pixelformat for both images !!! different format will change the pixel access and might also change the RGB order which will lead to wrong weights during conversion to luminance/grayscale. The pixelformat is set during picture_load so do not forget to set it if you use different loading method...
Also for comparing the color you might do a histogram for each color channel separately and compare that ...
I used double to prevent (32 bit) integer overflow of avgdif but take in mind for high resolution even double is not safe.

Related

Get value from the parameter of a callback function

I am using a biometrics SDK. And I converted the headers to delphi to consume the dll.
It looks something like this:
const
{VrBio_EventType}
VRBIO_CAPTURE_EVENT_UNPLUG = $001; {Fingerprint scanner unplugged from the computer.}
VRBIO_CAPTURE_EVENT_PLUG = $002; {Fingerprint scanner plugged on the computer.}
VRBIO_CAPTURE_EVENT_REMOVED = $004; {Finger removed from the fingerprint scanner.}
VRBIO_CAPTURE_EVENT_PLACED = $008; {Finger placed on the fingerprint scanner.}
VRBIO_CAPTURE_EVENT_IMAGE_FRAME = $10; {A fingerprint frame was captured on the fingerprint scanner.}
VRBIO_CAPTURE_EVENT_IMAGE_CAPTURED = $020; {A fingerprint image was captured on the fingerprint scanner.}
VRBIO_CAPTURE_EVENT_FAKE_FINGER_DETECTED = $400; {A false finger has been detected on the sensor}
VRBIO_CAPTURE_EVENT_FAKE_FINGER_REMOVED = $800; {A false finger has been removed from the sensor}
type
(* Stores the parameters of the ISO 19794-4 image format. #see VGetReaderProperties #see VrBio_ReaderProperty
typedef struct
{
/** #see VrBio_ISO197944CompressionMode*/
int compressionMode;
/** #see VrBio_ISO197944ImpressionType*/
int impressionType;
/** #see VrBio_ISO197944FingerPosition*/
int fingerPosition;
}VrBio_ISO197944Parameters;
*)
PISO197944Parameters = ^TISO197944Parameters;
TISO197944Parameters = record
compressionMode: Integer; { #see VrBio_ISO197944CompressionMode}
impressionType: Integer; { #see VrBio_ISO197944ImpressionType}
fingerPosition: Integer; { #see VrBio_ISO197944FingerPosition}
end;
(* Represents a biometric image. #see VrBio_CaptureEventCallback \ref VSyncCapture
struct VrBio_BiometricImage
{
/** Image width.*/
int width;
/**Image height*/
int height;
/**Image resolution in dpi. For the obsolete functions, use pixels/cm.*/
int resolution;
/**Number of channels in the image. Fingerprint images should always be grayscale, so this value is always 1.*/
int channels;
/**Biometric modality.
* Always use VRBIO_BIOMETRIC_MODALITY_FINGERPRINT.
* \ref VrBio_BiometricModality.
*/
int biometricModality;
/**Scanner type.
* \ref VrBio_ScannerType.
*/
int scannerType;
/**Formato de imagem: Formato da imagem.
*\ ref VrBio_ImageFormat.*/
int imageFormat;
/**Size of the buffer*/
int bufferSize;
/**Compression rate. Valid for images that allow compression.
* \ref VrBio_CompressionRate
*/
int compressionRate;
/**Quality of the fingerprint image.
* \ref VrBio_FingerQuality
*/
int fingerQuality;
/** Only valid if the image if imageFormat is \ref VrBio_ImageFormat::VRBIO_IMAGEFORMAT_ISO19794_4
*\ref VrBio_ISO197944Parameters
*/
VrBio_ISO197944Parameters* ISO197944_parameters;
/** Buffer storing the pixels of the image.
The position(x,y,c) of a pixel is y*width*channels+x*channels+c.
*/
unsigned char* buffer;
/**Reserved for future use*/
void* reserved;
};
typedef struct VrBio_BiometricImage VrBio_BiometricImage;
*)
PBiometricImage = ^TBiometricImage;
TBiometricImage = record
width: Integer; { Image width. }
height: Integer; { Image height }
resolution: Integer; { Image resolution in dpi. For the obsolete functions, use pixels/cm.}
channels: Integer; { Number of channels in the image. Fingerprint images should always be grayscale, so this value is always 1. }
biometricModality: Integer; { Biometric modality. Always use VRBIO_BIOMETRIC_MODALITY_FINGERPRINT. \ref VrBio_BiometricModality. }
scannerType: Integer; { Scanner type. \ref VrBio_ScannerType. }
imageFormat: Integer; { Formato de imagem: Formato da imagem. \ ref VrBio_ImageFormat. }
bufferSize: Integer; { Size of the buffer }
compressionRate: Integer; { Compression rate. Valid for images that allow compression. \ref VrBio_CompressionRate }
fingerQuality: Integer; { Quality of the fingerprint image. \ref VrBio_FingerQuality }
ISO197944_parameters: PISO197944Parameters; { Only valid if the image if imageFormat is \ref VrBio_ImageFormat::VRBIO_IMAGEFORMAT_ISO19794_4 \ref VrBio_ISO197944Parameters }
buffer: PByte; { Buffer storing the pixels of the image. The position(x,y,c) of a pixel is y*width*channels+x*channels+c. }
reserved: Pointer; { Reserved for future use }
end;
(*
#include "VTypes.h"
#ifdef WIN32
#define DLLIMPORT extern "C" __declspec(dllimport) int __stdcall
#else
#define DLLIMPORT extern "C"
#endif
*)
{ Callback function that receives events..
typedef void (*VrBio_CaptureEventCallback) (
int eventType,
const char* readerName,
VrBio_BiometricImage* image,
const void* userData)
}
TCaptureEventCallback = procedure(eventType: Integer; readerName: PAnsiChar; image: PBiometricImage; userData: Pointer); stdcall;
{ Function responsible for initializing the SDK. This function MUST be called before calling any other method, except \ref VInstallLicense
DLLIMPORT VStartSDK(VrBio_CaptureEventCallback eventCallback);
}
function VStartSDK(eventCallback: TCaptureEventCallback): Integer; stdcall;
{ Function responsible for finalizing the SDK. This function should be called when the SDK is not needed in the application anymore.
DLLIMPORT VStopSDK();
}
function VStopSDK(): Integer; stdcall;
{ Function responsible for starting the capture on a specific fingerprint reader.
After calling this function, the application is able to receive events.
DLLIMPORT VStartReader(const char* readerName);
}
function VStartReader(readerName: PAnsiChar): Integer; stdcall;
Using it looks like this:
implementation
{$R *.dfm}
procedure EventCallback(eventType: Integer; readerName: PAnsiChar; image: PBiometricImage; userData: Pointer); stdcall;
begin
case eventType of
VRBIO_CAPTURE_EVENT_UNPLUG: Form1.Memo1.Lines.Add('Leitor desconectado!');
VRBIO_CAPTURE_EVENT_REMOVED: Form1.Memo1.Lines.Add('Dedo removido!');
VRBIO_CAPTURE_EVENT_PLACED: Form1.Memo1.Lines.Add('Dedo detectado!');
VRBIO_CAPTURE_EVENT_IMAGE_FRAME: Form1.Memo1.Lines.Add('Frame capturado!');
VRBIO_CAPTURE_EVENT_IMAGE_CAPTURED: Form1.Memo1.Lines.Add('Imagem capturada!');
VRBIO_CAPTURE_EVENT_FAKE_FINGER_DETECTED: Form1.Memo1.Lines.Add('Dedo falso detectado!');
VRBIO_CAPTURE_EVENT_FAKE_FINGER_REMOVED: Form1.Memo1.Lines.Add('Dedo falso removido!');
VRBIO_CAPTURE_EVENT_PLUG:
begin
VStartReader(readerName);
Form1.Memo1.Lines.Add('Leitor conectado!');
end;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
VStartSDK(EventCallback);
end;
My questions:
I can use the application and get the Plug, Unplug and Placed events, but when I get the Image Captured event I have an acces vilation.
In the events that are working the EventCallback parameter image is nil. Is the TBiometricImage record conversion correct?
How can I convert the TBiometricImage buffer to a TBitmap and display the captured image in a TImage?
when I get the Image Captured event I have an acces vilation. In the events that are working the EventCallback parameter image is nil. Is the TBiometricImage record conversion correct?
The individual fields are declared fine, but double check that the alignment and padding of your Delphi records match the same alignment and padding used by the structs in C/C++.
Also, more importantly, the VrBio_CaptureEventCallback typedef in C/C++ is declared without any calling convention specified, so it will use the compiler's default convention, which is usually __cdecl instead of __stdcall (can be configured in the compiler settings). In Delphi, you declared TCaptureEventCallback to use stdcall instead of cdecl. You have to make sure you match the calling conventions correctly (the exported DLL functions do use stdcall, so you are OK there).
How can I convert the TBiometricImage buffer to a TBitmap and display the captured image in a TImage?
The SDK documentation does not explain how to process the various image formats. However, just looking at the struct declaration, the buffer field points at the actual image data, and the imageFormat field indicates the format of that data (there is a VrBio_ImageFormat enum that you have not translated yet). So, you would have to look at the imageFormat first to know how to interpret the buffer.
I do see a VConvertImage() function available. So you should be able to convert images to BMP format, if they are not already. Based on the samples in the SDK, it looks like the buffer data might be a standard BMP file format, so you could try copying the buffer to a TMemoryStream and then use the TBitmap.LoadFromStream() method.
There are also GIF and JPG image formats available, which could be handled by TGIFImage and TJPEGImage, respectively, or even TWICImage, if you wanted to display scanned GIF/JPG images without having to convert them to BMP first. There is also a RAW image format available (which apparently your images are using), but there is no standard VCL TGraphic class to handle RAW images, but I think there might be some 3rd party classes floating around if you look around.
Otherwise, you might try converting the image data to BMP, if needed, and then pass the buffer to the Win32 API CreateBitmap/Indirect() or CreateDibSection() function, and then assign the resulting HBITMAP to the TBitmap.Handle property if successful.

byte array in arduino library

ok so here is one for you maybe simple but i am not so sure.
i have the following code and it may be clear what i wish to do by looking at the code.
Arduino.ino
RF myRF; //Creation of RF class.
const int dataSize = 500;
byte storedData[dataSize];
//array is populated through program then the following is called
myRF.populate(storedData);
RF.CCP
const int dataSize = 500;
byte recivedData[dataSize];
void RF::populate(byte reciveddata){
recivedData = reciveddata;
}
RF.H
#include Arduino.h
#ifndef RF_H
#define RF_H
class RF {
public:
RF();
~RF();
void recive();
void send();
void print();
void sendnew(byte Storeddata);
};
#endif
this is however producing an error "byte is not declared"
Hope its clear what i intend to do and hope you can help thanks.
There are two problems in your files:
h file:
#include Arduino.h
You should write
#include <Arduino.h>
c file:
const int dataSize = 500;
byte recivedData[dataSize];
void RF::populate(byte reciveddata){
recivedData = reciveddata;
}
Here you have a big problem. You are declaring recivedData here, but you want to assign it a value coming from another part of the program. This is not how it works.
IMO you have two ways to do this.
1) store just the pointer to the memory; this way is faster and occupies less memory than solution 2, but you have to ensure that the storedData variable you pass in the .ino file is not changed during the function
#include "RF.h" // I hope you already included this
byte *recivedData;
void RF::populate(byte *reciveddata){
recivedData = reciveddata;
}
2) copy the content of the received array to this array; this way you have a copy of the array, so you occupy twice the memory (but you can edit storedData without problems).
#include "RF.h" // I hope you already included this
const int dataSize = 500;
byte recivedData[dataSize];
int recivedDataLength;
void RF::populate(byte *reciveddata, int reciveddatalength){
recivedDataLength = (reciveddatalength>dataSize) ? dataSize : reciveddatalength;
for (int i = 0; i < recivedDataLength; i++)
recivedData[i] = reciveddata[i];
}

GLSL: binding Shader Storage Buffer Object

I'm binding a Shader Storage Buffer Object (SSBO) and use in the Fragment Shader. The bindings are fine, the buffer block is a multiple of vec4(4B) blocks as required by the specifications. However, the following code has an unexpected behavior. The variable 'datapoint' has the correct 'a' value, but the 'b,c,d' values are garbage.
I'm using an Nvidia Quadro K5000 with driver version 340.52.
struct data
{
int a;
float b;
float c;
float d;
};
// the same location '0' is used on the host
layout(std430, binding = 0) buffer MyBuffer
{
data mydata[];
}
data datapoint;
void main()
{
...
datapoint = mydata[some_index]; // some_index is withing range
...
}

BCB 6.0 "raised exception class EAccessViolation with message 'Access violation at address'"

I'm newer to C++. I have written some code, but when i run it, there's always this:
raised exception class
EAccessViolation with message 'Access
violation at address'
i don't understand this. Would you like to help me solve it? It's important to me. Really, really thank you!
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <math.h>
#include <conio.h>
#define k 2
#define minoffset 0.5
using namespace std;
struct Point
{
double X;
double Y;
};
vector<Point> dataprocess();
void k_means(vector<Point> points,int N);
double getdistance(Point p1,Point p2)
{ double distance;
distance=sqrt((p1.X-p2.X)*(p1.X-p2.X)+(p1.Y-p2.Y)*(p1.Y-p2.Y));
return distance;
}
int getmindis(Point p,Point means[])
{
int i;
int c;
double dis=getdistance(p,means[0]);
for(i=1;i<k;i++)
{
double term=getdistance(p,means[i]);
if(term<dis)
{
c=i;
dis=term;
}
}
return c;
}
Point getmeans(vector<Point> points)
{
int i;
double sumX,sumY;
Point p;
int M=points.size();
for(i=0;i<M;i++)
{
sumX=points[i].X;
sumY=points[i].Y;
}
p.X=sumX/M;
p.Y=sumY/M;
return p;
}
int main()
{ int N;
vector<Point> stars;
stars=dataprocess();
N=stars.size();
cout<<"the size is:"<<N<<endl;
k_means(stars,N);
getch();
}
vector<Point> dataprocess()
{
int i;
int N;
double x,y;
vector<Point> points;
Point p;
string import_file;
cout<<"input the filename:"<<endl;
cin>>import_file;
ifstream infile(import_file.c_str());
if(!infile)
{
cout<<"read error!"<<endl;
}
else
{
while(infile>>x>>y)
{
p.X=x;
p.Y=y;
points.push_back(p);
}
}
N=points.size();
cout<<"output the file data:"<<endl;
for(i=0;i<N;i++)
{
cout<<"the point"<<i+1<<"is:X="<<points[i].X<<" Y="<<points[i].Y<<endl;
}
return points;
}
void k_means(vector<Point> points,int N)
{
int i;
int j;
int index;
vector<Point> clusters[k];
Point means[k];
Point newmeans[k];
double d,offset=0;
bool flag=1;
cout<<"there will be"<<k<<"clusters,input the original means:"<<endl;
for(i=0;i<k;i++)
{
cout<<"k"<<i+1<<":"<<endl;
cin>>means[i].X>>means[i].Y;
}
while(flag)
{
for(i=0;i<N;i++)
{
index=getmindis(points[i],means);
clusters[index].push_back(points[i]);
}
for(j=0;j<k;j++)
{
newmeans[j]=getmeans(clusters[j]);
offset=getdistance(newmeans[j],means[j]);
}
if(offset>d)
{
d=offset;
}
flag=(minoffset<d)?true:false;
for(i=0;i<k;i++)
{
means[i]=newmeans[i];
clusters[i].clear();
}
}
for(i=0;i<k;i++)
{
cout<<"N"<<i+1<<"="<<clusters[i].size()<<endl;
cout<<"the center of k"<<i+1<<"is:"<<means[i].X<<" "<<means[i].Y<< endl;
}
}
You surely have some algo errors in you code. It is difficult to deal with code without input data, that caused an error, but let's try:
First, lets look at function Point getmeans(vector<Point> points)
it is supposed to evaluate mean coordinates for cluster of points: if you pass an empty cluster to this function it will cause an error:
look here -
int M=points.size()
and here -
for(i=0;i<M;i++)
{
sumX=points[i].X;
sumY=points[i].Y;
}
if your cluster is empty than M will be zero and you loop will iterate 2^31 times (until 32 bit integer overflow) and each time you will try to read values of nonexistent vector items
So, You have to test if you vector is not empty before running main function loop and you have to decide which mean values should be assigned for zero cluster (May be you need an additional flag for empty cluster which will be checked before dealing with cluster's mean values)
Then lets examine function int getmindis(Point p,Point means[]) and, also, a place, where we call it:
index=getmindis(points[i],means); clusters[index].push_back(points[i]);
This function assings points to clusters. cluster number is ruled by c variable. If input point doesn't fit to any cluster, function will return uninitialized variable (holding any possible value) which. then is used as vector index of nonexisting element - possible access violation error
You probably have to initialize c to zero in declaration
Tell us when you will be ready with errors described above and also show us a sample input file (one which causes errors, if all datasets cause errors, show us the smallest one)

Displaying mesh using DirectX 9 - Mesh differences

This is my program to display a .x mesh. I am able to display the mesh tiger.x but not able to display ball.x. What is the difference between the two meshes? Is there something I should handle in the code? But I am able to view both the meshes using standard mesh viewers like the one which come with DirectX SDK.
Thanks.
but not able to display ball.x.
The question is unclear. Does the mesh load? Does it contain vertices/faces? Or maybe it crashes app? Or loading fails?
What is the difference between the two meshes?
The difference is that the second mesh (ball.x) doesn't include "templates".
I.e. this part:
template Header {
<3D82AB43-62DA-11cf-AB39-0020AF71E433>
WORD major;
WORD minor;
DWORD flags;
}
template Vector {
<3D82AB5E-62DA-11cf-AB39-0020AF71E433>
FLOAT x;
FLOAT y;
FLOAT z;
}
template Coords2d {
<F6F23F44-7686-11cf-8F52-0040333594A3>
FLOAT u;
FLOAT v;
}
template Matrix4x4 {
<F6F23F45-7686-11cf-8F52-0040333594A3>
array FLOAT matrix[16];
}
template ColorRGBA {
<35FF44E0-6C7C-11cf-8F52-0040333594A3>
FLOAT red;
FLOAT green;
FLOAT blue;
FLOAT alpha;
}
template ColorRGB {
<D3E16E81-7835-11cf-8F52-0040333594A3>
FLOAT red;
FLOAT green;
FLOAT blue;
}
template IndexedColor {
<1630B820-7842-11cf-8F52-0040333594A3>
DWORD index;
ColorRGBA indexColor;
}
template Boolean {
<4885AE61-78E8-11cf-8F52-0040333594A3>
WORD truefalse;
}
template Boolean2d {
<4885AE63-78E8-11cf-8F52-0040333594A3>
Boolean u;
Boolean v;
}
template MaterialWrap {
<4885AE60-78E8-11cf-8F52-0040333594A3>
Boolean u;
Boolean v;
}
template TextureFilename {
<A42790E1-7810-11cf-8F52-0040333594A3>
STRING filename;
}
template Material {
<3D82AB4D-62DA-11cf-AB39-0020AF71E433>
ColorRGBA faceColor;
FLOAT power;
ColorRGB specularColor;
ColorRGB emissiveColor;
[...]
}
template MeshFace {
<3D82AB5F-62DA-11cf-AB39-0020AF71E433>
DWORD nFaceVertexIndices;
array DWORD faceVertexIndices[nFaceVertexIndices];
}
template MeshFaceWraps {
<4885AE62-78E8-11cf-8F52-0040333594A3>
DWORD nFaceWrapValues;
Boolean2d faceWrapValues;
}
template MeshTextureCoords {
<F6F23F40-7686-11cf-8F52-0040333594A3>
DWORD nTextureCoords;
array Coords2d textureCoords[nTextureCoords];
}
template MeshMaterialList {
<F6F23F42-7686-11cf-8F52-0040333594A3>
DWORD nMaterials;
DWORD nFaceIndexes;
array DWORD faceIndexes[nFaceIndexes];
[Material]
}
template MeshNormals {
<F6F23F43-7686-11cf-8F52-0040333594A3>
DWORD nNormals;
array Vector normals[nNormals];
DWORD nFaceNormals;
array MeshFace faceNormals[nFaceNormals];
}
template MeshVertexColors {
<1630B821-7842-11cf-8F52-0040333594A3>
DWORD nVertexColors;
array IndexedColor vertexColors[nVertexColors];
}
template Mesh {
<3D82AB44-62DA-11cf-AB39-0020AF71E433>
DWORD nVertices;
array Vector vertices[nVertices];
DWORD nFaces;
array MeshFace faces[nFaces];
[...]
}
template FrameTransformMatrix {
<F6F23F41-7686-11cf-8F52-0040333594A3>
Matrix4x4 frameMatrix;
}
I.e. templates/structure declarations.
Also, in ball.x mesh is a part of hierarchy of Frames. In tiger.x it isn't, and is stored on top level of hierarchy.
It's been a while since I last used *.x file directly, but as far as I know, you'll need to include templates for all "non standard" templates into file. i.e. if file uses an object with template that wasn't registred using RegisterTemplates method of ID3DXFile or IDirectXFile, then the file won't load if template isn't written at the beginning of file. Try adding template definitions for every suspicious structure in ball.x , until you find the culprit . I'd start with "Header".
If the problem is because of hierarchy, you'll need to try another loading method.
using standard mesh viewers like the one which come with DirectX SDK.
AFAIK, mesh viewer comes with source code. Read the source and see how it works.
The mesh does not have any issue but the view. It was too zoomed in to display the image. I projected the image using the following matrix and was able to view the mesh properly.
//Set Projection
D3DXMATRIXA16 matProj(1.0,0.0,0.0,0.0,
0.0,1.0,0.0,0.0,
0.0,0.0,1.0,0.0,
0.0,0.0,0.0,150.0);

Resources