Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: Need some help to load Quake MDL Model files

  1. #1
    Newbie Newbie
    Join Date
    Dec 2017
    Posts
    2

    Need some help to load Quake MDL Model files

    Hello guys, i'm new to this forum, but i started OpenGL since few weeks. This week, i need to end my quake mdl viewer, but even after following this tutorial: http://tfc.duke.free.fr/coding/mdl-specs-en.html
    i'm always blocked, nothing of interesting appears on the screen. I wrote that with Java, and i use code::blocks next to eclipse, to compare values, but scale and translate vectors seems to be unsynchronized. Here are my classes, if you need the 3d model, tell me, i'll upload it. Thanks in advance !
    Code :
    package fr.plaigon.mdlloader;
     
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
     
    import org.lwjgl.util.vector.Vector3f;
     
    import com.google.common.io.LittleEndianDataInputStream;
     
    public class MDLReader
    {
    	public String filepath = "";
    	public String filename = "";
    	public MDLModel model = new MDLModel();
     
    	public MDLReader(String fileName)
    	{
    		loadobject(fileName);
    	}
     
    	public void loadobject(String objfilename)
    	{
    		if (objfilename != null && objfilename.length() > 0)
    		{
    			String[] pathParts = GLApp.getPathAndFile(objfilename);
    			filepath = pathParts[0];
    			filename = pathParts[1];
     
    			try
    			{
    				loadobject(GLApp.getInputStream(objfilename));
    			}
    			catch (Exception e)
    			{
    				System.out.println("MDLReader.loadobject(): Failed to read file: " + objfilename + " " + e);
    			}
    		}
    	}
     
    	public void loadobject(InputStream in)
    	{
    		if (in != null)
    		{
    			int numVertices, numTris, numFrames;
    			int skinWidth, skinHeight;
    			FileInputStream fis = (FileInputStream)in;
    			try
    			{
    				LittleEndianDataInputStream dis = new LittleEndianDataInputStream(fis);
     
    				//Header start
    				this.model.header.ident = dis.readInt();
    				this.model.header.version = dis.readInt();
     
    				this.model.header.scale = new Vector3f(dis.readFloat(), dis.readFloat(), dis.readFloat());
    				this.model.header.translate = new Vector3f(dis.readFloat(), dis.readFloat(), dis.readFloat());
     
    				this.model.header.boundingRadius = dis.readFloat();
     
    				this.model.header.eyePosition = new Vector3f(dis.readFloat(), dis.readFloat(), dis.readFloat());
     
    				this.model.header.numSkins = dis.readInt();
    				this.model.header.skinWidth = dis.readInt();
    				this.model.header.skinHeight = dis.readInt();
    				this.model.header.numVertices = dis.readInt();
    				this.model.header.numTriangles = dis.readInt();
    				this.model.header.numFrames = dis.readInt();
     
    				this.model.header.syncType = dis.readInt();
    				this.model.header.flags = dis.readInt();
    				this.model.header.size = dis.readFloat();
    				//Header end
     
    				this.model.texturesID = new int[this.model.header.numSkins];
    				this.model.skinInfo.group = dis.readInt();
    				byte[] dataArray = new byte[this.model.header.skinWidth * this.model.header.skinHeight];
    				dis.readFully(dataArray);
    				this.model.skinInfo.dataArray = dataArray;
    //				this.model.texturesID[0] = this.model.makeTextureFromSkin();
     
    				TexCoord[] texCoordsArray = new TexCoord[this.model.header.numVertices];
    				for(int i = 0; i < texCoordsArray.length; i++)
    				{
    					int onSeam = dis.readInt();
    					int s = dis.readInt();
    					int t = dis.readInt();
    					TexCoord texCoord = new TexCoord(onSeam, s, t);
    					texCoordsArray[i] = texCoord;
     
     
    				}
    				this.model.textureCoordinates = texCoordsArray;
     
    				Triangle[] trianglesArray = new Triangle[this.model.header.numTriangles];
    				for(int i = 0; i < trianglesArray.length; i++)
    				{
    					int facesFront = dis.readInt();
    					int[] verticesIndices = new int[] {dis.readInt(), dis.readInt(), dis.readInt()};
    					Triangle triangle = new Triangle(facesFront, verticesIndices);
    					trianglesArray[i] = triangle;
    				}
    				this.model.triangles = trianglesArray;
     
    				Frame[] framesArray = new Frame[this.model.header.numFrames];
    				for(int i = 0; i < framesArray.length; i++)
    				{
    					dis.readInt();//type ( 0 = simple, !0 = groupe ==> mdl_groupframe_t)
     
    					int[] bboxMinCoordinates = new int[] {dis.read(), dis.read(), dis.read()};
    //					System.out.println(new StringBuilder("bboxmin vertex coordinates: ").append("x: " + bboxMinCoordinates[0]).append(" y: " + bboxMinCoordinates[1]).append(" z: " + bboxMinCoordinates[2]).toString());
    					Vertex bboxMin = new Vertex(bboxMinCoordinates, dis.read());
    					int[] bboxMaxCoordinates = new int[] {dis.read(), dis.read(), dis.read()};
    //					System.out.println(new StringBuilder("bboxmax vertex coordinates: ").append("x: " + bboxMaxCoordinates[0]).append(" y: " + bboxMaxCoordinates[1]).append(" z: " + bboxMaxCoordinates[2]).toString());
    					Vertex bboxMax = new Vertex(bboxMaxCoordinates, dis.read());
     
    					byte[] name = new byte[16];
    					dis.readFully(name);
    					String frameName = new String(name);//frame's name
     
    					Vertex[] verticesArray = new Vertex[this.model.header.numVertices];
    					for(int i2 = 0; i2 < verticesArray.length; i2++)
    					{
    						int coordinates[] = new int[] {dis.read(), dis.read(), dis.read()};
    						verticesArray[i2] = new Vertex(coordinates, dis.read());
    					}
    					framesArray[i] = new Frame(bboxMin, bboxMax, frameName, verticesArray);
    				}
    				this.model.frames = framesArray;
     
    				dis.close();
    				fis.close();
    			}
    			catch (IOException e)
    			{
    				e.printStackTrace();
    			}
    		}
    	}
    }

    Main class:
    Code :
    package fr.plaigon;
     
    import org.lwjgl.opengl.Display;
    import org.lwjgl.opengl.DisplayMode;
    import org.lwjgl.util.glu.GLU;
    import org.lwjgl.util.vector.Vector3f;
     
    import fr.plaigon.mdlloader.MDLImporter;
    import fr.plaigon.mdlloader.MDLReader;
    import static org.lwjgl.opengl.GL11.*;
     
    import org.lwjgl.LWJGLException;
    import org.lwjgl.Sys;
    import org.lwjgl.input.Keyboard;
    import org.lwjgl.input.Mouse;
     
    public class MDLMainFrame
    {
    	private long lastFrame;
    	private Vector3f rotation = new Vector3f();
    	private Vector3f location = new Vector3f();
     
    	private final MDLImporter modelImporter = new MDLImporter();
     
    	public MDLMainFrame()
    	{
    		this.init();
    		setUpDisplay();
     
    		glMatrixMode(GL_PROJECTION);
    		glLoadIdentity();
    		GLU.gluPerspective(30f, (float) (640 / 480), 0.3f, 100f);
    		glMatrixMode(GL_MODELVIEW);
    		glEnable(GL_DEPTH_TEST);
     
    		getDelta();
    		while (!Display.isCloseRequested()) {
    			int delta = getDelta();
     
    			render(delta);
    			checkInput();
    			Display.update();
    			Display.sync(60);
    		}
    		System.exit(0);
    	}
     
    	public static void main(String[] args)
    	{
    		new MDLMainFrame();
    	}
     
    	private void setUpDisplay()
    	{
    		try
    		{
    			Display.setDisplayMode(new DisplayMode(640, 480));
    			Display.setVSyncEnabled(true);
    			Display.setResizable(true);
    			Display.setTitle("Happy Easter!");
    			Display.create();
    		}
    		catch (LWJGLException e)
    		{
    			System.err.println("The display wasn't initialized correctly. :(");
    			Display.destroy();
    			System.exit(1);
    		}
    	}
     
        /** 
         * Calculate how many milliseconds have passed 
         * since last frame.
         * 
         * @return milliseconds passed since last frame 
         */
        public int getDelta() {
            long time = getTime();
            int delta = (int) (time - lastFrame);
            lastFrame = time;
     
            return delta;
        }
     
        /**
         * Get the accurate system time
         * 
         * @return The system time in milliseconds
         */
        public long getTime() {
            return (Sys.getTime() * 1000) / Sys.getTimerResolution();
        }
     
        private void render(int delta)
    	{
        	glPushMatrix();
    		glEnable(GL_CULL_FACE);
    	    glCullFace(GL_BACK);
    		glEnable(GL_DEPTH_TEST);
        	glEnable(GL_ALPHA_TEST);
    //    	glAlphaFunc(GL_GREATER, 0.5F);
    		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    		glColor3f(1f, 1f, 1f);
     
    		glEnable(GL_TEXTURE_2D);                     
     
    //	    glShadeModel(GL_SMOOTH);
    //	    glDepthFunc(GL_LESS);
    //	    glDepthMask(true);
    //	    glEnable(GL_NORMALIZE); 
    	    //enable lighting
    //	    glEnable(GL_LIGHTING);
     
    //		glRotatef(rotation.x, 1, 0, 0);
    //		glRotatef(rotation.y, 0, 1, 0);
    //		glRotatef(rotation.z, 0, 0, 1);
    //		glTranslatef(location.x, location.y, location.z);
    		this.modelImporter.reader.model.renderFrame(0);
    //		this.RenderCube();
    		glPopMatrix();
    	}
     
    	private void checkInput() 
    	{	
    		boolean up = Keyboard.isKeyDown(Keyboard.KEY_W);
    		boolean down = Keyboard.isKeyDown(Keyboard.KEY_S);
    		boolean left = Keyboard.isKeyDown(Keyboard.KEY_A);
    		boolean right = Keyboard.isKeyDown(Keyboard.KEY_D);
    		boolean flyUp = Keyboard.isKeyDown(Keyboard.KEY_E);
    		boolean flyDown = Keyboard.isKeyDown(Keyboard.KEY_Q);
    		boolean speedUp = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT);
    		boolean slowDown = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL);
    		float walkSpeed = 0.15F;
     
    		float mx = Mouse.getDX();
    		float my = Mouse.getDY();
    		mx *= 0.25F;
    		my *= 0.25F;
    		rotation.y += mx;
    		if(rotation.y > 360)
    			rotation.y -= 360;
     
    		rotation.x -= my;
    		if(rotation.x > 85)
    			rotation.x = 85;
    		if(rotation.x < -85)
    			rotation.x = -85;
     
    		if(speedUp && !slowDown)
    			walkSpeed = 0.25F;
    		if(slowDown && !speedUp)
    			walkSpeed = 0.10F;
     
    		if(up && !down)
    		{
    			float cz  = (float) (walkSpeed * 2 * Math.cos(Math.toRadians(rotation.y)));
    			float cx  = (float) (walkSpeed * Math.sin(Math.toRadians(rotation.y)));
    			location.z += cz;
    			location.x -= cx;
    		}
    		if(down && !up)
    		{
    			float cz  = (float) (walkSpeed * 2 * Math.cos(Math.toRadians(rotation.y)));
    			float cx  = (float) (walkSpeed * Math.sin(Math.toRadians(rotation.y)));
    			location.z -= cz;
    			location.x += cx;
    		}
    		if(right && !left)
    		{
    			float cz  = (float) (walkSpeed * 2 * Math.cos(Math.toRadians(rotation.y + 90)));
    			float cx  = (float) (walkSpeed * Math.sin(Math.toRadians(rotation.y)));
    			location.z += cz;
    			location.x -= cx;
    		}
    		if(left && !right)
    		{
    			float cz  = (float) (walkSpeed * 2 * Math.cos(Math.toRadians(rotation.y + 90)));
    			float cx  = (float) (walkSpeed * Math.sin(Math.toRadians(rotation.y)));
    			location.z -= cz;
    			location.x += cx;
    		}
     
    		if(flyUp && !flyDown)
    			location.y -= walkSpeed;
    		if(flyDown && !flyUp)
    			location.y += walkSpeed;
    	}
     
    	private void init()
    	{
    		this.modelImporter.load("res/mdl/B_BB110out.mdl");
    		System.out.println(this.modelImporter.reader.model.header);
    //		-48
    //		-497
    //		-321
     
    //		1073741824
    //		536870912
    //		-1610612736
    	}
     
    	private void RenderCube() {
     
    		glTranslatef(0f + location.x, 0.0f + location.y, -7f + location.z);
    		glRotatef(45f, 0.0f, 1.0f, 0.0f);
    		glColor3f(0.5f, 0.5f, 1.0f);
     
    		glBegin(GL_QUADS);
    		glColor3f(1.0f, 1.0f, 0.0f);
    		glVertex3f(1.0f, 1.0f, -1.0f);
    		glVertex3f(-1.0f, 1.0f, -1.0f);
    		glVertex3f(-1.0f, 1.0f, 1.0f);
    		glVertex3f(1.0f, 1.0f, 1.0f);
    		glColor3f(1.0f, 0.5f, 0.0f);
    		glVertex3f(1.0f, -1.0f, 1.0f);
    		glVertex3f(-1.0f, -1.0f, 1.0f);
    		glVertex3f(-1.0f, -1.0f, -1.0f);
    		glVertex3f(1.0f, -1.0f, -1.0f);
    		glColor3f(1.0f, 0.0f, 0.0f);
    		glVertex3f(1.0f, 1.0f, 1.0f);
    		glVertex3f(-1.0f, 1.0f, 1.0f);
    		glVertex3f(-1.0f, -1.0f, 1.0f);
    		glVertex3f(1.0f, -1.0f, 1.0f);
    		glColor3f(1.0f, 1.0f, 0.0f);
    		glVertex3f(1.0f, -1.0f, -1.0f);
    		glVertex3f(-1.0f, -1.0f, -1.0f);
    		glVertex3f(-1.0f, 1.0f, -1.0f);
    		glVertex3f(1.0f, 1.0f, -1.0f);
    		glColor3f(0.0f, 0.0f, 1.0f);
    		glVertex3f(-1.0f, 1.0f, 1.0f);
    		glVertex3f(-1.0f, 1.0f, -1.0f);
    		glVertex3f(-1.0f, -1.0f, -1.0f);
    		glVertex3f(-1.0f, -1.0f, 1.0f);
    		glColor3f(1.0f, 0.0f, 1.0f);
    		glVertex3f(1.0f, 1.0f, -1.0f);
    		glVertex3f(1.0f, 1.0f, 1.0f);
    		glVertex3f(1.0f, -1.0f, 1.0f);
    		glVertex3f(1.0f, -1.0f, -1.0f);
    		glEnd();
     
    	}
    }

    And MDLModel:
    Code :
    package fr.plaigon.mdlloader;
     
    import static org.lwjgl.opengl.GL11.GL_LINEAR;
    import static org.lwjgl.opengl.GL11.GL_REPEAT;
    import static org.lwjgl.opengl.GL11.GL_RGB;
    import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
    import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
    import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
    import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
    import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
    import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
    import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
    import static org.lwjgl.opengl.GL11.glBegin;
    import static org.lwjgl.opengl.GL11.glBindTexture;
    import static org.lwjgl.opengl.GL11.glColor3f;
    import static org.lwjgl.opengl.GL11.glEnd;
    import static org.lwjgl.opengl.GL11.glGenTextures;
    import static org.lwjgl.opengl.GL11.glTexParameteri;
    import static org.lwjgl.opengl.GL11.glVertex3f;
     
    import java.io.BufferedReader;
    import java.io.ByteArrayOutputStream;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.nio.ByteBuffer;
     
    import org.lwjgl.util.glu.GLU;
    import org.lwjgl.util.vector.Vector3f;
     
    public class MDLModel
    {
    	public static final File COLOR_MAP = new File("res/mdl/colormap.txt");
     
    	public TexCoord[] textureCoordinates;
    	public int[] texturesID;
    	public Triangle[] triangles;
    	public Frame[] frames;
    	public Header header = new Header();
    	public SkinTextInformation skinInfo = new SkinTextInformation();
     
    	public class Header
    	{
    		public int ident;//identifier or "magical number"
    		public int version;//usually 6
    		public Vector3f scale;//Scale model vector
    		public Vector3f translate;//Translation model vector
    		public float boundingRadius;//Sphere radius from a minimum radius in which the model can be put
    		public Vector3f eyePosition;//Eyes model vector
    		public int numSkins, skinWidth, skinHeight;
    		public int numVertices, numTriangles, numFrames;
    		public int syncType, flags;
    		public float size;//average size of triangles
     
    		@Override
    		public String toString()
    		{
    			StringBuilder result = new StringBuilder("Header vars from requested mdl quake model are:").append("\n -ident or magic number: " + this.ident).append("\n -version: " + this.version)
    					.append("\n -scale vector: " + this.scale).append("\n -translate vector: " + this.translate).append("\n -bounding radius: " + this.boundingRadius).append("\n -eyes position vector: " + this.eyePosition)
    					.append("\n -numSkins: " + this.numSkins).append("\n -skinWidth: " + this.skinWidth).append("\n -skin height: " + this.skinHeight).append("\n -numVertices: " + this.numVertices)
    					.append("\n -numTriangles: " + this.numTriangles).append("\n -numFrames: " + this.numFrames).append("\n -sync type: " + this.syncType).append("\n -flags: " + this.flags).append("\n -size: " + this.size);
    			return result.toString();
    		}
    	}
     
    	public class SkinTextInformation
    	{
    		public int group;//0 = simple, !0 = groupe
    		public byte[] dataArray;
    	}
     
    	public void renderFrame(int n)
    	{
    		if ((n < 0) || (n > this.header.numFrames - 1))//Car n démarre à 0
    		{
    			System.out.println("n in invalid range !");
    			return;
    		}
     
    		glBindTexture(GL_TEXTURE_2D, this.texturesID[0]);
     
    		glBegin(GL_TRIANGLES);
    		for(int i = 0; i < this.header.numTriangles; i++)
    		{
    			for(int j = 0; j < 3; j++)
    			{
    				Vertex vert = this.frames[0].verticesArray[this.triangles[i].verticesIndices[j]];
     
    //				vert.coordinates[0] = (int)(-1610612736 * vert.coordinates[0]) + 1073741824;
    //				vert.coordinates[1] = (int)(536870912 * vert.coordinates[1]) + 536870912;
    //				vert.coordinates[2] = (int)(1610612736 * vert.coordinates[2]) + -1610612736;
     
    				glColor3f((-1610612736 * vert.coordinates[0]) + 1073741824, (536870912 * vert.coordinates[1]) + 536870912, (1610612736 * vert.coordinates[2]) + -1610612736);
    				glVertex3f((-1610612736 * vert.coordinates[0]) + 1073741824, (536870912 * vert.coordinates[1]) + 536870912, (1610612736 * vert.coordinates[2]) + -1610612736);
    			}
    		}
    		glEnd();
    	}
     
    	public int makeTextureFromSkin()
    	{
    		int[] pixels = new int[this.header.skinWidth * this.header.skinHeight * 3];
     
    		//Convert indexed 8 bits texture to RGB 24 bits
    		for(int i = 0; i < this.header.skinWidth * this.header.skinHeight; i++)
    		{
    			pixels[(i * 3) + 0] = this.getRGBValueFromPalette( ((i + 1) % 4) == 0 ? (i + 1) / 4 : ( (int)(i / 4) + 1), ((i + 1)% 4) == 0 ? 3 : ((int)i % 4))[0];
    			pixels[(i * 3) + 1] = this.getRGBValueFromPalette( ((i + 1) % 4) == 0 ? (i + 1) / 4 : ( (int)(i / 4) + 1), ((i + 1)% 4) == 0 ? 3 : ((int)i % 4))[1];
    			pixels[(i * 3) + 2] = this.getRGBValueFromPalette( ((i + 1) % 4) == 0 ? (i + 1) / 4 : ( (int)(i / 4) + 1), ((i + 1)% 4) == 0 ? 3 : ((int)i % 4))[2];
    		}
    		this.texturesID[0] = glGenTextures();
    		glBindTexture(GL_TEXTURE_2D, this.texturesID[0]);
     
    		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
     
    		ByteBuffer buffer = ByteBuffer.wrap(this.integersToBytes(pixels));
    		GLU.gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, this.header.skinWidth, this.header.skinHeight, GL_RGB, GL_UNSIGNED_BYTE, buffer);
    		return 0;
    	}
     
    	private byte[] integersToBytes(int[] values)
    	{
    	   ByteArrayOutputStream baos = new ByteArrayOutputStream();
    	   DataOutputStream dos = new DataOutputStream(baos);
    	   for(int i=0; i < values.length; ++i)
    	   {
    	        try
    	        {
    				dos.writeInt(values[i]);
    			}
    	        catch (IOException e)
    	        {
    				e.printStackTrace();
    			}
    	   }
     
    	   return baos.toByteArray();
    	}  
     
    	public int[] getRGBValueFromPalette(int l, int c)
    	{
    		if(l < 1 || l > 64)
    		{
    			System.out.println("line out of palette text file");
    			return new int[] {0, 0, 0};
    		}
    		if(c < 0 || c > 3)
    		{
    			System.out.println("column out of palette text file");
    			return new int[] {0, 0, 0};
    		}
     
    		int[] rgbValues = new int[3];
    		try
    		{
    			BufferedReader reader = new BufferedReader(new InputStreamReader(new DataInputStream(new FileInputStream(MDLModel.COLOR_MAP))));
    			try
    			{
    				String line = "";
    				for(int i = 0; i < l; i++)
    					line = reader.readLine();
     
    				rgbValues[0] = Integer.valueOf(splitInEqualParts(line, 4)[c].replaceAll(",", " ").substring(1, 4).trim());
    				rgbValues[1] = Integer.valueOf(splitInEqualParts(line, 4)[c].replaceAll(",", " ").substring(5, 9).trim());
    				rgbValues[2] = 	Integer.valueOf(splitInEqualParts(line, 4)[c].replaceAll(",", " ").substring(10, 14).trim());
    			}
    			catch (IOException e)
    			{
    				e.printStackTrace();
    			}
    		}
    		catch (FileNotFoundException e)
    		{
    			e.printStackTrace();
    		}
    		return rgbValues;
    	}
     
    	private String[] splitInEqualParts(final String s, final int n)
    	{
    	    if(s == null)
    	        return null;
    	    final int strlen = s.length();
    	    if(strlen < n)
    	    {
    	        // this could be handled differently
    	        throw new IllegalArgumentException("String too short");
    	    }
    	    final String[] arr = new String[n];
    	    final int tokensize = strlen / n + (strlen % n == 0 ? 0 : 1);
    	    for(int i = 0; i < n; i++)
    	    {
    	        arr[i] = s.substring(i * tokensize, Math.min((i + 1) * tokensize, strlen));
    	    }
    	    return arr;
    	}
    }

  2. #2
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,728
    Have you looked at the Quake source code? It might be a helpful reference. https://github.com/id-Software/Quake..._model.c#L1489

  3. #3
    Newbie Newbie
    Join Date
    Dec 2017
    Posts
    2
    Thanks for your answer, but the tutorial explains all of that, all of reading binary mdl file. I juste need help about rendering vertices. I know that's very easy, but i started a while ago, so i'm not able to see what i did wrong :/

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •