08-04-2025, 03:49 AM
So, I need to calculate surface normals which are stored compressed and need to some math I don't get yet so i gave Googles AI my code for all types and everything for loading and drawing the model and asked it to write me some code to do the task...3 seconds and poof! I got this...its VB but that's close enough for me to convert easily! Scary thing is, its coded very much like i would do it....
Its a brave new world folks!
Unseen
Code: (Select All)
vb
' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' // Function to decode an MD3 compressed normal integer into a 3D vector
' // Input: compressedNormal_Integer - The integer from GDK_GL_MD3_Vertex.Normal
' // Output: GDK_GL_MD3_Vector_3 representing the decoded normal vector
' // (Note: This is a common decoding method, but may vary slightly based on specific MD3 implementations)
' // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
FUNCTION DecodeMD3Normal (compressedNormal_Integer AS INTEGER) AS GDK_GL_MD3_Vector_3
DIM NormalVector AS GDK_GL_MD3_Vector_3
' // The integer is typically broken into two 8-bit values (one for longitude, one for latitude)
' // Shift bits to get the individual angle values
DIM lat AS INTEGER ' // Latitude angle index
DIM lon AS INTEGER ' // Longitude angle index
lat = (compressedNormal_Integer >> 8) AND &HFF ' // Extract the upper 8 bits (latitude)
lon = compressedNormal_Integer AND &HFF ' // Extract the lower 8 bits (longitude)
' // Convert angle indices to radians. MD3 uses 255 steps for 360 degrees (or 2*PI radians)
DIM lat_rad AS SINGLE
DIM lon_rad AS SINGLE
lat_rad = lat * (2 * 3.14159265 / 255)
lon_rad = lon * (2 * 3.14159265 / 255)
' // Calculate X, Y, Z components from spherical coordinates
' // Standard conversion:
' // X = cos(latitude) * sin(longitude)
' // Y = sin(latitude)
' // Z = cos(latitude) * cos(longitude)
' // However, Q3/MD3 often uses a different convention (e.g., Y and Z might be swapped or negated)
' // based on their coordinate system. You might need to adjust this.
' // For Quake 3: Z is usually up, but the models are often exported with Y up.
' // This conversion assumes Y is 'up' and adjusts for potential Q3 peculiarities.
DIM CosLat AS SINGLE = COS(lat_rad)
DIM SinLat AS SINGLE = SIN(lat_rad)
DIM CosLon AS SINGLE = COS(lon_rad)
DIM SinLon AS SINGLE = SIN(lon_rad)
NormalVector.X = CosLat * SinLon
NormalVector.Y = SinLat
NormalVector.Z = CosLat * CosLon
' // You might need to swap Y and Z, or negate one, depending on your desired coordinate system.
' // For example, if you want Z to be "up":
' // DIM TmpY AS SINGLE = NormalVector.Y
' // NormalVector.Y = NormalVector.Z
' // NormalVector.Z = TmpY
' // Or possibly: NormalVector.Y = -NormalVector.Y
FUNCTION = NormalVector
END FUNCTION
' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' // Function to normalize a 3D vector (make its length 1)
' // Input: vec - The vector to normalize
' // Output: The normalized vector
' // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
FUNCTION NormalizeVector (vec AS GDK_GL_MD3_Vector_3) AS GDK_GL_MD3_Vector_3
DIM ResultVec AS GDK_GL_MD3_Vector_3
DIM Length AS SINGLE = SQR((vec.X * vec.X) + (vec.Y * vec.Y) + (vec.Z * vec.Z))
IF Length > 0 THEN
ResultVec.X = vec.X / Length
ResultVec.Y = vec.Y / Length
ResultVec.Z = vec.Z / Length
ELSE
' // Handle zero-length vector (e.g., return (0,0,0) or throw an error)
ResultVec.X = 0
ResultVec.Y = 0
ResultVec.Z = 0
END IF
FUNCTION = ResultVec
END FUNCTION
' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' // Function to perform a vector subtraction (V2 - V1)
' // Input: V1, V2 - The two vectors
' // Output: The resulting vector (V2 - V1)
' // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
FUNCTION VectorSubtract (V1 AS GDK_GL_MD3_Vector_3, V2 AS GDK_GL_MD3_Vector_3) AS GDK_GL_MD3_Vector_3
DIM ResultVec AS GDK_GL_MD3_Vector_3
ResultVec.X = V2.X - V1.X
ResultVec.Y = V2.Y - V1.Y
ResultVec.Z = V2.Z - V1.Z
FUNCTION = ResultVec
END FUNCTION
' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' // Function to perform a vector cross product (U x V)
' // Input: U, V - The two vectors
' // Output: The resulting perpendicular vector
' // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
FUNCTION VectorCrossProduct (U AS GDK_GL_MD3_Vector_3, V AS GDK_GL_MD3_Vector_3) AS GDK_GL_MD3_Vector_3
DIM ResultVec AS GDK_GL_MD3_Vector_3
ResultVec.X = (U.Y * V.Z) - (U.Z * V.Y)
ResultVec.Y = (U.Z * V.X) - (U.X * V.Z)
ResultVec.Z = (U.X * V.Y) - (U.Y * V.X)
FUNCTION = ResultVec
END FUNCTION
' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' // Function to calculate the face normal of a triangle
' // Input: P1, P2, P3 - The three vertices of the triangle (in their float coordinates)
' // Output: The normalized face normal vector
' // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
FUNCTION CalculateFaceNormal (P1 AS GDK_GL_MD3_Vector_3, P2 AS GDK_GL_MD3_Vector_3, P3 AS GDK_GL_MD3_Vector_3) AS GDK_GL_MD3_Vector_3
DIM Edge1 AS GDK_GL_MD3_Vector_3
DIM Edge2 AS GDK_GL_MD3_Vector_3
DIM NormalVector AS GDK_GL_MD3_Vector_3
' // Calculate two edges of the triangle
Edge1 = VectorSubtract(P1, P2) ' // P2 - P1
Edge2 = VectorSubtract(P1, P3) ' // P3 - P1
' // Calculate the cross product to get the normal
NormalVector = VectorCrossProduct(Edge1, Edge2)
' // Normalize the normal vector (make its length 1)
NormalVector = NormalizeVector(NormalVector)
FUNCTION = NormalVector
END FUNCTION
Use code with caution.
Integrating into your Loading Logic
Integrate this into your loading loop. You'll need to allocate memory for the triangle data and load it as well. Assume that you've finished allocating Model.Vert_Data and Model.Tri_Data and loaded the corresponding arrays.
vb
' ( ... previous code ... )
Model.Vert_Data = _MEMNEW((LEN(GDK_GL_MD3_Vertex)) * (Total_Verts& * TmpMD3.Num_Frames))
' // You'll need to actually read the vertex data into a temporary array first, like MD3_Vertices
DIM MD3_Vertices((Total_Verts& * TmpMD3.Num_Frames) - 1) AS GDK_GL_MD3_Vertex
' // ... code to read all vertices from file into MD3_Vertices ...
' // This involves calculating offsets based on TmpMD3.Offset_Surfaces, MD3_Surface(j&).Offset_Vertices
' // and looping through frames and surfaces.
' // For simplicity in this example, let's assume MD3_Vertices() is populated with all vertices.
_MEMPUT Model.Vert_Data, Model.Vert_Data.OFFSET, MD3_Vertices()
Model.Tri_Data = _MEMNEW(LEN(GDK_GL_MD3_Triangle) * Total_Tris&)
DIM MD3_Triangles(Total_Tris& - 1) AS GDK_GL_MD3_Triangle
' // ... code to read all triangles from file into MD3_Triangles ...
' // This involves calculating offsets based on TmpMD3.Offset_Surfaces, MD3_Surface(j&).Offset_Triangles
' // and looping through surfaces.
' // For simplicity in this example, let's assume MD3_Triangles() is populated with all triangles.
_MEMPUT Model.Tri_Data, Model.Tri_Data.OFFSET, MD3_Triangles()
' // Allocate memory to store the calculated triangle normals (if needed separately)
' // Or you might integrate this into a more general data structure for rendering.
DIM CalculatedFaceNormals(Total_Tris& - 1) AS GDK_GL_MD3_Vector_3
DIM ProcessedVertices(Total_Verts& * TmpMD3.Num_Frames - 1) AS GDK_GL_MD3_Vector_3 ' // To store decoded vertices
' // First pass: Decode compressed vertex positions and normals
FOR i& = 0 TO (Total_Verts& * TmpMD3.Num_Frames) - 1
' // MD3 vertices are typically scaled and offset.
' // You'll need to reverse this process to get the actual float positions.
' // Assuming a common scale factor (e.g., 1/64) and potentially an offset.
' // For simplicity here, assume these are directly convertible or already converted.
ProcessedVertices(i&).X = MD3_Vertices(i&).X / 64.0 ' // Example scaling
ProcessedVertices(i&).Y = MD3_Vertices(i&).Y / 64.0
ProcessedVertices(i&).Z = MD3_Vertices(i&).Z / 64.0
' // You'd also decode the normal here if needed for direct vertex normal usage
' // ProcessedVerticesNormals(i&) = DecodeMD3Normal(MD3_Vertices(i&).Normal)
NEXT
' // Second pass: Calculate face normals for each triangle
FOR i& = 0 TO Total_Tris& - 1
DIM Tri AS GDK_GL_MD3_Triangle = MD3_Triangles(i&)
DIM P1_Index AS LONG = Tri.X
DIM P2_Index AS LONG = Tri.Y
DIM P3_Index AS LONG = Tri.Z
DIM P1_Pos AS GDK_GL_MD3_Vector_3 = ProcessedVertices(P1_Index)
DIM P2_Pos AS GDK_GL_MD3_Vector_3 = ProcessedVertices(P2_Index)
DIM P3_Pos AS GDK_GL_MD3_Vector_3 = ProcessedVertices(P3_Index)
CalculatedFaceNormals(i&) = CalculateFaceNormal(P1_Pos, P2_Pos, P3_Pos)
NEXT
' // ( ... continue with any further processing, e.g., storing CalculatedFaceNormals ... )
CLOSE #FFile&
END SUB
Use code with caution.
Its a brave new world folks!
Unseen

