Sign in to follow this  
zgintasz

Drawing infinite grid

Recommended Posts

I'm making a 2D map editor and I'm trying to make an infinite(pseudo of course) grid. And then later I need to check in which grid's square is the certain point(mouse pointer). The grid shouldn't stick on the screen like a GUI, user should see grid like so(like "scrolling"):
How can I do that?
P.S. I'm using winforms and opentk if it makes any sense.

Share this post


Link to post
Share on other sites

I'm not following what your problem is. Do you have the grid already? If so, you say you move the camera, what is the problem? Translating the camera or grid will achieve the same thing albeit in opposite directions. Or is the problem with rendering the grid?

Edited by GeneralQuery

Share this post


Link to post
Share on other sites

Are you asking how to do it using the tools you use (winforms/opentk?), or are you asking how to structure and code it (store unlimited amount of tiles, load them, show the correct ones at correct offset...)?

Share this post


Link to post
Share on other sites

Well, first of all you want to store the tiles in chunks. (lets say 32*32 tiles per chunk)

 

This way you can render the chunks that are visible, and you can create the chunks as you scroll further. Maybe even save chunks to disk if theres a problem with memory and theyre far away...

 

As you want infinite terrain, you cant really use a huge grid of those chunks (if you can without using up too much memory, its probably simpler that way. Depends how you define "infinite"). You want a tree like container to store them (quadtree or some kind of hash map container...) so you can store lets say the chunk at 3,6 and the one at 64,12553 and leave the left empty.

 

Then you need a camera, to represent where on top of the terrain you are looking at. From the position of the camera and the size of the screen, you can find a rectangle. Find the chunks inside the rectangle (convert the corners to chunk-coordinates, like chunk 1,1 or chunk 4,5, then get all the chunks in that rectangle...), then render them with the appropriate offset from the screen center (difference between the chunk position and camera position)

 

For starters, i would make a single chunk, and a camera, and make the chunk render in the right spot as you move the camera.

Share this post


Link to post
Share on other sites

You don't have to draw an infinite grid to make it look like one:

 

http://www.youtube.com/watch?v=oFV39F_ZJ3s

#include <GL/glfw.h>

int main(){
    int x, y, nx, ny, mx, my, lx, ly;
    int dx = 0;
    int dy = 0;
    int w = 512;
    int h = 512;
    int cell_w = 32;
    int cell_h = 32;

    glfwInit();
    glfwOpenWindow(w, h, 8, 8, 8, 8, 0, 0, GLFW_WINDOW);

    glfwGetMousePos(&lx, &ly);

    while (!glfwGetKey(GLFW_KEY_ESC)){
        glClear(GL_COLOR_BUFFER_BIT);

        /* Make OpenGL cover full window size */
        glfwGetWindowSize(&w, &h);
        glViewport(0, 0, w, h);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, w, h, 0, -1, 1);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        /* Handle mouse input */
        glfwGetMousePos(&mx, &my);
        if (glfwGetMouseButton(GLFW_MOUSE_BUTTON_LEFT)){
            /* Offset the grid by the distance the mouse moved */
            dx += mx - lx;
            dy += my - ly;
            /* Use the %-operator to jump back */
            dx %= cell_w;
            dy %= cell_h;

            float r = 10.0f;
            glRectf(mx-r, my-r, mx+r, my+r);
        }
        lx = mx;
        ly = my;

        glTranslatef(dx, dy, 0.0f);

        /* Draw a grid which is a little bigger than the screen */
        nx = w/cell_w + 2;
        ny = h/cell_h + 2;
        glBegin(GL_LINES);
        for (x=0; x<nx; x++){
            glVertex2f(x*cell_w,  -cell_h);
            glVertex2f(x*cell_w, h+cell_h);
        }
        for (y=0; y<ny; y++){
            glVertex2f( -cell_w, y*cell_h);
            glVertex2f(w+cell_w, y*cell_h);
        }
        glEnd();

        glfwSwapBuffers();
    }
    glfwTerminate();
    return 0;
}

This is deprecated OpenGL. With a fragment shader this would be much easier (but much harder to setup).

Share this post


Link to post
Share on other sites

What have you tried?

I knew somebody will ask that question biggrin.png.

After a few hours of thinking I finally almost completed it, there is only one issue left:

http://tinypic.com/player.php?v=6h55wl&s=6

sorry for that terrible quality(I can try to record it again if needed...), but as you can see the grid doesn't follow the screen very well.


I'll be very thankful if someone will help me fixing that problem.

I've just started learning opengl few weeks ago, so I don't know everything very well...

Here is my code(grid class, code is a probably a mess right now, I will tidy it after fixing that problem):

 

    public class grid
    {
        private MainWindow mainWindow;
        
        public float viewWidth;
        public float viewHeight;
        public Point cameraPos;

        public Rectangle glview;
        public int WidthItems { get; set; }
        public int HeightItems { get; set; }
        public Rectangle[] squares;
        private int totalSquares;
        private int squareSize = 75;

        public grid(MainWindow window, int widthitems, int heightitems, int ViewWidth, int ViewHeight)
        {
            mainWindow = window;
            cameraPos = new Point(0, 0);
            viewWidth = ViewWidth;
            viewHeight = ViewHeight;
            WidthItems = (int)(viewHeight / squareSize);
            HeightItems = (int)(viewWidth / squareSize);
            totalSquares = WidthItems * HeightItems;
            squares = new Rectangle[totalSquares];
        }
        public Point CalculateViewCenterPos()
        {
            return mainWindow.convertScreenToWorldCoords((0 + glview.Width) / 2, (0 + glview.Height) / 2);
        }
        float tempOffsetX = 0f, tempOffsetY = 0f;
        float offsetX = 0f, offsetY = 0f;
        public void CameraMoved(float x, float y)
        {
            tempOffsetX += x;
            if (tempOffsetX > squareSize)
            {
                offsetX -= squareSize;
                tempOffsetX = 0;
            }
            else if (tempOffsetX < -squareSize)
            {
                offsetX += squareSize;
                tempOffsetX = 0;
            }
            tempOffsetY += y;
            if (tempOffsetY > squareSize)
            {
                offsetY -= squareSize;
                tempOffsetY = 0;
            }
            else if (tempOffsetY < -squareSize)
            {
                offsetY += squareSize;
                tempOffsetY = 0;
            }
        }
        public void calculateCoords()
        {
            Point topleft = mainWindow.convertScreenToWorldCoords(0, 0);
            mainWindow.testclickX = topleft.X;
            mainWindow.testclickY = topleft.Y;

            int startPosX = topleft.X - squareSize * 2;
            int startPosY = topleft.Y + squareSize;
            int id = 0;
            for (int i = 0; i < WidthItems; i++)
            {
                for (int j = 0; j < HeightItems; j++)
                {
                    squares[id].X = startPosX;
                    squares[id].Y = startPosY;
                    startPosX += squareSize;
                    id++;
                }
                startPosX = topleft.X - squareSize * 2;
                startPosY -= squareSize;
            }
        }
        public void draw()
        {
            for (int i = 0; i < totalSquares; i++)
            {
                GL.Color3(Color.Green);
                GL.PushMatrix();
                GL.Begin(BeginMode.Lines);
                GL.Vertex3(squares[i].X + offsetX, squares[i].Y + offsetY, -2);
                GL.Vertex3(squares[i].X + offsetX, squares[i].Y + squareSize + offsetY, -2);

                GL.Vertex3(squares[i].X + offsetX, squares[i].Y + offsetY, -2);
                GL.Vertex3(squares[i].X + squareSize + offsetX, squares[i].Y + offsetY, -2);

                GL.Vertex3(squares[i].X + squareSize + offsetX, squares[i].Y + squareSize + offsetY, -2);
                GL.Vertex3(squares[i].X + offsetX, squares[i].Y + squareSize + offsetY, -2);

                GL.Vertex3(squares[i].X + squareSize + offsetX, squares[i].Y + squareSize + offsetY, -2);
                GL.Vertex3(squares[i].X + squareSize + offsetX, squares[i].Y + offsetY, -2);
                GL.End();
                GL.PopMatrix();
            }
        }
    }

and MainWindow class:

 

                // ...
                grid maingrid;
                // ...
                maingrid.draw();
                // ...
                glviewRatio = (ClientRectangle.Width / zoom) / (ClientRectangle.Height / zoom) * 5;
                // ...
                maingrid = new grid(this, 50, 50, ClientRectangle.Width * 5 / zoom, ClientRectangle.Height * 5 / zoom);
                maingrid.glview = new Rectangle(glview.Location.X, glview.Location.Y, glview.Size.Width, glview.Size.Height);
                maingrid.calculateCoords();
                // ...
                // (every frame when mouse button is clicked)
                float x = (MousePosition.X - started_mouse_pos.X) * glviewRatio / zoom;
                float y = -(MousePosition.Y - started_mouse_pos.Y) * glviewRatio / zoom;
                maingrid.CameraMoved(x, y);
                started_mouse_pos.X = MousePosition.X;
                started_mouse_pos.Y = MousePosition.Y;
Edited by zgintasz

Share this post


Link to post
Share on other sites

Finally, found the solution myself smile.png. Just changed CameraMoved function:

        public static void CameraMoved(float x, float y)
        {
            tempOffsetX += x;
            tempOffsetY += y;
            while (tempOffsetX >= squareSize)
            {
                offsetX -= squareSize;
                tempOffsetX -= squareSize;
            }
            while (tempOffsetX <= -squareSize)
            {
                offsetX += squareSize;
                tempOffsetX += squareSize;
            }
            while (tempOffsetY >= squareSize)
            {
                offsetY -= squareSize;
                tempOffsetY -= squareSize;
            }
            while (tempOffsetY <= -squareSize)
            {
                offsetY += squareSize;
                tempOffsetY += squareSize;
            }
        }
Edited by zgintasz

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this