Merci pour ta réponse rapide Cpl.Bator.
En ce qui concerne la texture, je la crée en cours de route avec un damier de couleur.
Effectivement, les coords UV des vertices sont stockées dans une zone mémoire et en doublon dans une liste chaînée pour vérif.
Pour le code, le voici (en vrac et avec des commentaires en anglais approximatif vu que je pensais le poster sur le forum anglais)
Souris pour orienter la camera, Molette pour soomer et clic gauche pour sortir
Code : Tout sélectionner
; ".x" file loader
;{ Structures
Structure s_Vertex
vx.f
vy.f
vz.f
u.f
v.f
EndStructure
;Structure s_Face
;vertindex.w[3]
;EndStructure
;}
Global NewList Vertices.s_Vertex()
;Global NewList Face.s_Face()
Declare.s GetString(nbchar.l)
Declare RechercheStr(find$)
Declare ParseMesh(num.w)
;{ Global variables definition
Global nb.w
Global Addr.l
Global AddrFin.l
Global type$ ; ="t" for text file or "b" for binary file
Global float.b ; =4 for 32 bits (float) or 8 for 64 bits (double)
Global NLines.l
Global NWords.l
Global CurrentDirectory.s
Global EOL.s
Global AsciiConv, Allwords, UniqueWords, WordCount
Global MemFileOffset.l, MemFileSize.l, *FileBuffer
;}
;{ Arrays declaration
Dim AsciiConv.s(255)
Dim AllWords.s(10000000)
Dim UniqueWords.s(1000000)
Dim WordCount.l(1000000)
;}
;{ Constants declaration
#FileType1=$786F6620 ;"xof " Big endian
#Filetype2=$30333032 ;"0302"
#Filetype3bin=$62696E20 ;"bin "
#Filetype3txt=$74787420 ;"txt "
#Filetype4=$00003332 ; Float 32 or 64
#TOKEN_NAME=1
#TOKEN_STRING=2
#TOKEN_INTEGER=3
#TOKEN_GUID=5
#TOKEN_INTEGER_LIST=6
#TOKEN_FLOAT_LIST=7
#TOKEN_OBRACE=10
#TOKEN_CBRACE=11
#TOKEN_OPAREN=12
#TOKEN_CPAREN=13
#TOKEN_OBRACKET=14
#TOKEN_CBRACKET=15
#TOKEN_OANGLE=16
#TOKEN_CANGLE=17
#TOKEN_DOT=18
#TOKEN_COMMA=19
#TOKEN_SEMICOLON=20
#TOKEN_TEMPLATE=31
#TOKEN_WORD=40
#TOKEN_DWORD=41
#TOKEN_FLOAT=42
#TOKEN_DOUBLE=43
#TOKEN_CHAR=44
#TOKEN_UCHAR=45
#TOKEN_SWORD=46
#TOKEN_SDWORD=47
#TOKEN_VOID=48
#TOKEN_LPSTR=49
#TOKEN_UNICODE=50
#TOKEN_CSTRING=51
#TOKEN_ARRAY=52
;}
;{ Common procedures
;
;Declare SkipTemplateMembers()
Procedure FatalError(t$)
MessageRequester("Fatal Error",t$,#PB_MessageRequester_Ok)
End
EndProcedure
Procedure.l LoadFileToMem(fileID,fname.s)
;Protected fileID,fname
If ReadFile(fileID,fname)
MemFileSize = Lof(fileID)
;Debug "MemFileSize = " + Str(MemFileSize)
*FileBuffer = AllocateMemory(MemFileSize)
If *FileBuffer
ReadData(fileID,*FileBuffer,MemFileSize)
EndIf
CloseFile(fileID)
;Debug "FileBuffer = " + Str(*FileBuffer)
MemFileOffset = 0 ; reset
EndIf
ProcedureReturn *FileBuffer
EndProcedure
Procedure MoreInMem()
If MemFileOffset < MemFileSize
ok = 1
EndIf
ProcedureReturn ok
EndProcedure
Procedure.s ReadLineFromMem() ; in case EOF: empty line is returned
If *FileBuffer And MoreInMem()
Start = *FileBuffer + MemFileOffset
Length = 0
Repeat
Length + 1
Byte.b = PeekB(Start + Length)
Until Byte = 13 Or Byte = 10 Or MemFileOffset + Length >= MemFileSize
EndIf
Skip = 1
Byte = PeekB(Start + Length + 1)
If Byte = 10 Or Byte = 13
Length + 1
Skip + 1
EndIf
MemFileOffset + Length
ProcedureReturn PeekS(Start + 1, Length - Skip)
EndProcedure
Procedure CloseFileMem()
FreeMemory(*FileBuffer)
EndProcedure
Procedure InvBits(valeur.l,type) ;transforme little endian en big endian 1 Word 2 Dword
If type=1 ; word
BigEnd=(((valeur & $00FF)<<8) | ((valeur & $FF00)>>8)) & $FFFF
If BigEnd>$8000
BigEnd=BigEnd-$10000
EndIf
ProcedureReturn BigEnd
ElseIf type=2 ; Long
BigEnd=(((valeur<<24) & $FF000000) | ((valeur<<8) & $00FF0000) | ((valeur>>8) & $0000FF00) | ((valeur>>24) & $000000FF))
If BigEnd>$80000000
BigEnd=BigEnd-$100000000
EndIf
ProcedureReturn BigEnd
EndIf
EndProcedure
Procedure ParseHeader() ; Lit le header du fichier et garde les infos importantes
If GetString(4)="xof "
Addr=Addr+4 ; skip version number
t$=GetString(4)
If t$="txt "
type$="t"
ElseIf t$="bin "
type$="b"
EndIf
t$=GetString(4)
If t$="0032"
float.b=4
ElseIf t$="0064"
float.b=8
EndIf
EndIf
EndProcedure
Procedure LoadXFile(a$)
Addr.l=LoadFileToMem(0,a$)
If Addr=0
FatalError("Memory Allocation failed")
EndIf
AddrFin.l=Addr.l+MemFileSize.l
ParseHeader()
If type$="t"
FatalError("X File is text format - Not supported yet")
EndIf
;
; boucle de traitement principal
;
nbdep.w=nb
Repeat
;
a=RechercheStr("Mesh"); returns 1 if mesh found, 0 if End of file reached without finding more meshes
If a=1 ; If Mesh found
nb=nb+1 ; Count one more Mesh
ParseMesh(nb-1) ; Deals with mesh infos (vertices, faces, normals, UV, etc)
EndIf ; else EndOfFile is reached
Until Addr>=AddrFin-10
If nb-nbdep=0
FatalError("No mesh in file")
EndIf
CloseFileMem() ; frees X file Buffer
; sets up datas according to type of mesh (boat.x, rudder.x, etc)
;f$=LCase(GetFilePart(a$))
;If f$="boat.x"
;EndIf
; sets up materials and meshes
;LoadTexture(0,"wave0.bmp")
CreateTexture(0,512,512)
StartDrawing(TextureOutput(0))
For xt=0 To 7 Step 2
For yt=0 To 7 Step 2
Box(xt*16,yt*16,16,16,$FFFF00)
Next
Next
StopDrawing()
CreateMaterial(0,TextureID(0))
MaterialAmbientColor(0,#PB_Material_AmbientColors)
For i =0 To nb-1
If IsMesh(i)
a=CreateEntity(i,MeshID(i),MaterialID(0),0,0,0)
EndIf
Next
EndProcedure
;}
;{ Binary parser procedures
Procedure.b GetByte() ; Reads a BYTE at Addr and increases this adress by one
a.b=PeekB(Addr)
Addr=Addr+1
ProcedureReturn a.b
EndProcedure
Procedure.w GetWord() ; Reads a WORD at Addr and increases this adress by two
;a.w=InvBits(PeekW(Addr),1)
a.w=PeekW(Addr)
Addr=Addr+2
ProcedureReturn a.w
EndProcedure
Procedure.l GetDWord() ; Reads a DWORD (or long) at Addr and increases this adress by four
;a.l=InvBits(PeekL(Addr),2)
a.l=PeekL(Addr)
Addr=Addr+4
ProcedureReturn a.l
EndProcedure
Procedure.d GetDouble() ; Reads a DOUBLE at Addr and increases this adress by eight
a.d=PeekW(Addr)
Addr=Addr+8
ProcedureReturn a.d
EndProcedure
Procedure.f GetFloat() ; Reads a FLOAT at Addr and increases this adress by four
;a.f=InvBits(PeekF(Addr),2)
a.f=PeekF(Addr)
Addr=Addr+4
ProcedureReturn a.f
EndProcedure
Procedure.s GetString(nbchar.l); Reads a nbchar character string at Addr and increases this adress by nbchar
a.s=PeekS(Addr,nbchar,#PB_Ascii)
Addr=Addr+nbchar
ProcedureReturn a.s
EndProcedure
Procedure.s GetName() ; Reads a Template name and his length at Addr and increases this adress by his length
long.l=PeekL(addr)
Addr=Addr+8
nom$=getstring(long)
ProcedureReturn nom$
EndProcedure
Procedure RechercheStr(find$) ; Finds find$ from Addr (Global) up to AddrFin (Global) and increases Addr
Fin=0
While Addr<=AddrFin-10 And Fin=0
If GetWord()=$0001 ;+2
If GetDWord()=Len(find$) ;+4
If GetString(Len(find$))=find$ ;+4
ProcedureReturn 1
Fin=1
Else
Addr=Addr-9
EndIf
Else
Addr=Addr-5
EndIf
Else
Addr=Addr-1
EndIf
Wend
EndProcedure
Procedure RechercheStrTo(find$,stop$) ; Finds find$ from Addr (Global) up to AddrFin (Global) or meet stop$ and increases Addr
Fin=0
While Addr<=AddrFin-10 And Fin=0
If GetWord()=$0001 ;+2
t=GetDWord()
If t=Len(find$) Or t=Len(stop$) ;+4
If GetString(Len(find$))=find$ ;+?
ProcedureReturn 1
Fin=1
Else
Addr=Addr-9
EndIf
If GetString(Len(stop$))=stop$
ProcedureReturn 0
Fin=1
Else
Addr=Addr-9
EndIf
Else
Addr=Addr-5
EndIf
Else
Addr=Addr-1
EndIf
Wend
EndProcedure
Procedure ParseMesh(num.w) ; Once Mesh is found, reads data and creates relevant PB Mesh
;**********************************************
; retrieves name of the mesh or creates one
If GetWord()=#TOKEN_NAME
n$=GetString(GetDWord())
Else
n$="Object"+StrU(num,1)
Addr=Addr-2
EndIf
t=GetDWord(); must be #TOKEN_OBRACE + #TOKEN_INTEGER_LIST
t=GetDWord(); must be $00000001 ; only one element : vertices number count
;**********************************************
; retrieves vertices count in mesh
nbVertices.l=GetDWord() ; retrieves number of vertices in the mesh
CreateMesh(num,3000) ;nbVertices.l) ; creates empty PB mesh
;If result=0
; ProcedureReturn 0
;EndIf
GetWord() ; must be #TOKEN_FLOAT_LIST ; avoid token
;**********************************************
; retrieves vertices coords in X mesh and set PB mesh with this coords
If float=4 ; if float size=32 as defined in header (4 bytes length)
nbCoords.l=GetDWord() ; must be 3x nbVertices
MemVert=AllocateMemory(nbCoords*4)
If MemVert=0
End
EndIf
Pointer.l=MemVert
For i.l=1 To nbVertices.l
AddElement(Vertices())
Vertices()\vx=GetFloat()
PokeF(pointer,Vertices()\vx)
pointer=pointer+4
Vertices()\vy=GetFloat()
PokeF(pointer,Vertices()\vy)
pointer=pointer+4
Vertices()\vz=getfloat()
PokeF(pointer,Vertices()\vz)
pointer=pointer+4
Next
SetMeshData(num,#PB_Mesh_Vertex,MemVert,nbVertices)
FreeMemory(MemVert)
Else ; if float size in header=64 (Double with 8 bytes length) : NOT SUPPORTED YET
nbCoords.l=GetDWord() ; must be 3x nbVertices
For i.l=1 To nbVertices.l
x.d=GetDouble()
y.d=GetDouble()
z.d=GetDouble()
Next
EndIf
;CallDebugger
GetWord() ; must be 0006 #TOKEN_INTEGER_LIST
GetDWord() ; must be 4xnbfaces+1(nbfaces)
;**********************************************
; retrieves triangles count in mesh
nbFaces.l=GetDWord() ; retreives number of faces defined
adbuff.l=AllocateMemory(nbFaces*4*4) ; allocates generous memory for temp buffer (convert list DWORD->WORD)
If adbuff<>0 ; if allocation is oK
buff.l=adbuff ; keep track of the start of the buffer
;long.l=0 ; keeps exact length of data in buffer Not Needed = Faces Count
For i=1 To nbFaces ; Until all triangles are done
nbv.l=GetDWord() ; Retrieves number of vertices for current face (hope it is 3)
For j=1 To nbv.l ; Until all verticess for current face are sighted
temp=GetDWord() ; gets vertex index (DWORD) from X file
PokeW(buff,temp) ; takes it in buffer (WORD)
a=PeekW(buff) ; for debugging only
buff=buff+2 ; points to next WORD in buffer
;long=long+1 ; data length in buffer is increased by 1
Next ; Vertices loop
;long=long+1
Next ; Triangles loop
SetMeshData(num,#PB_Mesh_Face,adbuff,nbFaces) ; set PB mesh triangles from buffer
FreeMemory(adbuff) ; deallocate buffer
EndIf
;**********************************************
; retrieves UV Coords in mesh
AddTemp.l=Addr ; saves current pointer to be able to scan for other meshes
Repeat
;
a=RechercheStrTo("MeshTextureCoords","Mesh"); returns 1 if UV found, 0 if End of file or meet next mesh
If a=1 ; If UV found
t.l=GetDWord(); must be #TOKEN_OBRACE + #TOKEN_INTEGER_LIST
t=GetDWord(); must be $00000001 ; only one element : vertices number count
;**********************************************
; retrieves vertices count in mesh
t=GetDWord() ; must be number of vertices in the mesh
GetWord() ; must be #TOKEN_FLOAT_LIST ; avoid token
;**********************************************
; retrieves UV coords in X mesh and set PB mesh with this coords
If float=4 ; if float size=32 as defined in header (4 bytes length)
nbCoords.l=GetDWord() ; must be 2x nbVertices
MemUV.l=AllocateMemory(nbVertices*2*4)
If MemUV=0
End
EndIf
Pointer.l=MemUV
ResetList(Vertices())
For i.l=1 To nbVertices.l
NextElement(Vertices())
Vertices()\u=GetFloat()
PokeF(pointer,Vertices()\u)
pointer=pointer+4
Vertices()\v=GetFloat()
PokeF(pointer,Vertices()\v)
pointer=pointer+4
Next
SetMeshData(num,#PB_Mesh_UVCoordinate,MemUV,nbVertices)
FreeMemory(MemUV)
Else ; if float size in header=64 (Double with 8 bytes length) : NOT SUPPORTED YET
nbCoords.l=GetDWord() ; must be 3x nbVertices
For i.l=1 To nbVertices.l
x.d=GetDouble()
y.d=GetDouble()
z.d=GetDouble()
Next
EndIf
Else
Addr=AddrFin
EndIf
Until Addr>=AddrFin-10
Addr=AddTemp ; restores good value of Addr to scan for other meshes
EndProcedure
;}
;{ Text parser procedures
Procedure.s Tgetstring()
EndProcedure
Procedure.b TGetByte()
EndProcedure
Procedure.w TGetWord()
EndProcedure
Procedure.l TGetDWord()
EndProcedure
Procedure.d TGetDouble()
EndProcedure
Procedure.f TGetFloat()
EndProcedure
Procedure TRechercheStr(find$)
EndProcedure
Procedure TAddMesh(num.w)
EndProcedure
;}
;************************************************************************************
; Program Start
;************************************************************************************
If InitEngine3D()=0 Or InitSprite()=0 Or InitKeyboard()=0 Or InitMouse()=0
FatalError("Initialisation failed")
EndIf
OpenWindow(0,0,0,640,480,"3D View",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,640,480,0,0,0)
HideWindow(0,1)
;a$=OpenFileRequester("selectionner un fichier DirectX","*.x","*.x",0)
;If a$=""
; FatalError("Le fichier est introuvable")
;EndIf
;
a$ = "prop.X"
LoadXFile(a$)
HideWindow(0,0)
CreateLight(0,RGB($ff,$ff,$ff),0,0,0)
CreateCamera(0,0,0,100,100)
CameraBackColor(0,RGB(150,150,150))
CameraProjection(0,#PB_Camera_Perspective)
;CameraRenderMode(0,#PB_Camera_Plot) ;#PB_Camera_Plot #PB_Camera_Wireframe #PB_Camera_Textured
AmbientColor(RGB($ff,$ff,$ff))
CameraLookAt(0,0,0,0)
CameraFOV(0,45)
anglex.w=0
angley.w=0
anglez.w=0
distance.l=1000
CameraRange(0,1,distance*2)
ExamineMouse()
mx=MouseDeltaX()
my=MouseDeltaY()
mw=MouseWheel()
;Left Mouse click waiting loop
While MouseButton(#PB_MouseButton_Left)=0
ExamineMouse()
mx=MouseDeltaX()
my=MouseDeltaY()
mw=MouseWheel()*-40
If mw<>0
If distance>50
distance=distance+mw
Else
If mw>0
distance=distance+mw
Else
distance=50
EndIf
EndIf
CameraRange(0,1,distance*2)
Else
mx=mx/2
my=my/2
anglexy=(anglexy+mx)%360;
anglez=(anglez+my)%360;
axyrad.f=(anglexy/360)*6.283185
azrad.f=(anglez/360)*6.283185
x.f=Cos(axyrad)*distance
z.f=Sin(axyrad)*distance
y.f=Sin(azrad)*distance
EndIf
CameraLocate(0,x,y,z)
CameraLookAt(0,0,0,0)
LightLocate(0,x,y,z)
ClearScreen(RGB(50,50,50))
RenderWorld()
StartDrawing(ScreenOutput())
DrawText(0,0,"x :"+Str(anglexy),RGB($ff,$ff,$ff),RGB(0,0,0))
DrawText(0,20,"y :"+Str(anglexy),RGB($ff,$ff,$ff),RGB(0,0,0))
DrawText(0,40,"z :"+Str(anglez),RGB($ff,$ff,$ff),RGB(0,0,0))
DrawText(0,60,StrU(distance,2),RGB($ff,$ff,$ff),RGB(0,0,0))
StopDrawing()
FlipBuffers()
If IsScreenActive()=1
ReleaseMouse(0)
Else
ReleaseMouse(1)
EndIf
Wend
CloseScreen()
CloseWindow(0)
End
Si quelqu'un y retrouve ses petits ...