a1.gui.GUI_Map.java Source code

Java tutorial

Introduction

Here is the source code for a1.gui.GUI_Map.java

Source

/*
 * This file is part of the Origin-World game client.
 * Copyright (C) 2012 Arkadiy Fattakhov <ark@ark.su>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package a1.gui;

import a1.*;
import a1.utils.Rect;
import a1.utils.Resource;
import org.lwjgl.BufferUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.EXTFramebufferObject;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GLContext;
import org.newdawn.slick.Color;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.*;

import static a1.MapCache.TILE_SIZE;
import static a1.net.NetGame.SEND_map_click;
import static org.lwjgl.opengl.GL11.*;

public class GUI_Map extends GUI_Control {

    public static int VBO_SIZE = 80000;
    public static int tile_vboSize = VBO_SIZE * 4 * 4;
    //
    public static int tileGrid_vboSize = VBO_SIZE * 4 * 2;
    //
    public static int claim_vboSize = 1000 * 6 * 4;

    public static float[] tile_vboUpdate = new float[tile_vboSize];
    public static float[] tileGrid_vboUpdate = new float[tile_vboSize];
    public static float[] claim_vboUpdate = new float[tile_vboSize];
    public static int tile_Offset = 0;
    public static int tileGrid_Offset = 0;
    public static int claim_Offset = 0;
    //
    public static int tile_drawCount = 0;
    public static int tileGrid_drawCount = 0;
    public static int claim_drawCount = 0;
    private static int tile_vbo;
    private static int tileGrid_vbo;
    private static int claim_vbo;

    ///////////////
    public static boolean render_rects = false;
    public static boolean render_lightmap = false;
    public static boolean render_claims = true;
    /////////////////
    public static final Coord tile_tex_size = new Coord(50, 25);
    public static final Coord tilewall_tex_size = new Coord(64, 20);
    public int RenderedTiles = 0;
    public int RenderedObjects = 0;
    public static Map<String, Class<? extends Camera>> cameras = new TreeMap<String, Class<? extends Camera>>();
    public List<RenderPart> render_parts = new ArrayList<RenderPart>();
    public RenderPart[] clickable;
    public Obj mouse_in_object = null;
    public Coord mouse_tile_coord = Coord.z;
    public Coord mouse_map_pos = Coord.z;
    public Obj place_obj = null;

    public Camera camera = null;
    public Coord mc = Coord.z;
    public Coord player_coord = Coord.z;

    // ?   
    private boolean player_rendered;
    //    ?
    private Rect player_rect;
    public static final float OVERLAY_K = 0.33f;
    public static boolean ignore_overlapped = false;

    private long last_time_mouse_send = 0;
    private boolean mouse_left_pressed = false;
    private boolean mouse_middle_pressed = false;
    private Coord mouse_middle_press_coord;
    private boolean render_tiles = true;
    private boolean render_objects = true;
    private boolean gui_map_rendered = true;
    public static float scale = 1.0f;
    Coord scaled_size;
    public static boolean needUpdateView = true;

    static {
        cameras.put("fixed", FixedCam.class);
    }

    public GUI_Map(GUI_Control parent) {
        super(parent);
        GUI.map = this;
        SetSize(Config.getScreenWidth(), Config.getScreenHeight());
        scale = 1.0f;
        scaled_size = new Coord(Config.getScreenWidth(), Config.getScreenHeight()).mul(1 / scale);
        set_camera("fixed");
        initVBO();
    }

    private void initVBO() {
        tile_vbo = GL15.glGenBuffers();
        tileGrid_vbo = GL15.glGenBuffers();
        claim_vbo = GL15.glGenBuffers();

        FloatBuffer data = BufferUtils.createFloatBuffer(tile_vboSize);

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, tile_vbo);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_DYNAMIC_DRAW);

        data = BufferUtils.createFloatBuffer(tileGrid_vboSize);

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, tileGrid_vbo);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_DYNAMIC_DRAW);

        data = BufferUtils.createFloatBuffer(claim_vboSize);

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, claim_vbo);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_DYNAMIC_DRAW);

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
    }

    //  
    public void DoUpdate() {
        mouse_map_pos = s2m(gui.mouse_pos.mul(1 / scale).add(viewoffset(scaled_size, this.mc).inverse()));
        mouse_tile_coord = tilify(mouse_map_pos);

        FlyText.Update();

        Coord my = my_coord();
        if (!player_coord.equals(my)) {
            player_coord = my;
            needUpdateView = true;
            //         if (camera != null) {
            //            camera.reset();
            //         }
        }

        // move by mouse
        if (Config.move_inst_left_mouse && MouseInMe() && mouse_left_pressed
                && (System.currentTimeMillis() - last_time_mouse_send > 500)) {
            SendMapClick(Input.MB_LEFT);
        }

        if (Input.KeyHit(Keyboard.KEY_G) && Input.isCtrlPressed()) {
            Config.tile_grid = !Config.tile_grid;
            needUpdateView = true;
        }
        if (gui.focused_control == null) {
            if (Input.KeyHit(Keyboard.KEY_HOME) && !Input.isCtrlPressed() && camera != null) {
                camera.reset();
            }
            if (Input.KeyHit(Keyboard.KEY_HOME) && Input.isCtrlPressed()) {
                scale = 1.0f;
                updateScale();
            }

            if (Config.debug && Input.KeyHit(Keyboard.KEY_T) && Input.isCtrlPressed()) {
                render_tiles = !render_tiles;
            }

            if (Config.debug && Input.KeyHit(Keyboard.KEY_Y) && Input.isCtrlPressed()) {
                render_objects = !render_objects;
            }

            if (Config.debug && Input.KeyHit(Keyboard.KEY_U) && Input.isCtrlPressed()) {
                gui_map_rendered = !gui_map_rendered;
            }
        }

        if (camera != null) {
            if (get_player() != null)
                camera.setpos(this, get_player(), scaled_size);
            camera.update(this);
        }

        if (Input.KeyHit(org.newdawn.slick.Input.KEY_F2))
            render_rects = !render_rects;

        //      if (Input.KeyHit(org.newdawn.slick.Input.KEY_F4)) 
        //         render_lightmap = !render_lightmap;

        if (place_obj != null)
            place_obj.pos = new Coord(mouse_tile_coord);

        PrepareRenderParts();
        //PrepareTiles();
        // need sort parts in render list
        Collections.sort(render_parts, RenderPart.part_cmp);
    }

    public boolean DoMouseWheel(boolean isUp, int len) {
        if (!MouseInMe() || !Config.zoom_by_wheel)
            return false;

        float olds = scale;
        scale = scale + (isUp ? 1 : -1) * 0.1f * len;
        if (scale < 0.4f)
            scale = 0.4f;
        if (scale > 5.0f)
            scale = 5.0f;
        if (camera != null && Config.zoom_over_mouse)
            camera.scaled(this, olds);
        updateScale();
        return true;
    }

    private void updateScale() {
        needUpdateView = true;
        scaled_size = new Coord(Config.getScreenWidth(), Config.getScreenHeight()).mul(1 / scale);
    }

    @Override
    public void DoDestroy() {
        GL15.glDeleteBuffers(tile_vbo);
        GL15.glDeleteBuffers(tileGrid_vbo);
        GL15.glDeleteBuffers(claim_vbo);
        super.DoDestroy();
    }

    //  
    public void DoRender() {
        if (!gui_map_rendered)
            return;

        if (render_lightmap)
            CreateLightMap();

        RenderedObjects = 0;
        GL11.glPushMatrix();
        GL11.glScalef(scale, scale, 1.0f);
        if (render_tiles)
            DrawTiles();
        if (render_objects)
            DrawObjects();
        DrawFlyText();

        if (render_lightmap)
            RenderLightMap();
        GL11.glPopMatrix();

        if (Config.debug) {
            Render2D.Text("", 10, 200, "mc=" + mc.toString());
            if (mouse_in_object != null)
                Render2D.Text("", 10, 220, "obj=" + mouse_in_object.toString());
            if (mouse_map_pos != null)
                Render2D.Text("", 10, 240, "mouse_map_pos=" + mouse_map_pos.toString());
            if (mouse_tile_coord != null) {
                Render2D.Text("", 10, 260, "mouse_tile_coord=" + mouse_tile_coord.toString());
                Coord tc = mouse_tile_coord.div(TILE_SIZE);
                Render2D.Text("", 10, 280, "mouse_tile=" + tc.toString());
                Render2D.Text("", 10, 300, "mouse_tile_type=" + Integer.toString(MapCache.GetTile(tc)));
            }

            if (player_rect != null)
                Render2D.Text("", 10, 320, "player_rect=" + player_rect.toString());
            Render2D.Text("", 10, 340, "scale=" + String.valueOf(scale));
        }
    }

    private void updateVBO() {

        tile_drawCount = tile_Offset / 4;
        tileGrid_drawCount = tileGrid_Offset / 2;
        claim_drawCount = claim_Offset / 6;

        FloatBuffer data = BufferUtils.createFloatBuffer(tile_Offset);
        data.put(tile_vboUpdate, 0, tile_Offset);
        data.flip();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, tile_vbo);
        GL15.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, data);

        data = BufferUtils.createFloatBuffer(tileGrid_Offset);
        data.put(tileGrid_vboUpdate, 0, tileGrid_Offset);
        data.flip();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, tileGrid_vbo);
        GL15.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, data);

        data = BufferUtils.createFloatBuffer(claim_Offset);
        data.put(claim_vboUpdate, 0, claim_Offset);
        data.flip();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, claim_vbo);
        GL15.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, data);

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);

        tile_Offset = 0;
        tileGrid_Offset = 0;
        claim_Offset = 0;
    }

    //  ?  
    public boolean DoMouseBtn(int btn, boolean down) {
        if (btn == Input.MB_LEFT)
            mouse_left_pressed = MouseInMe() && down;
        if (!MouseInMe() && down)
            return false;

        if (btn == Input.MB_MIDDLE && MouseInMe())
            if (down) {
                mouse_middle_pressed = true;
                mouse_middle_press_coord = gui.mouse_pos.clone();
            } else {
                if (mouse_middle_pressed && gui.mouse_pos.dist(mouse_middle_press_coord) < 5) {
                    scale = 1.0f;
                    updateScale();
                }
            }

        //  
        if (camera != null) {
            if (camera.DoMouseBtn(this, gui.mouse_pos.mul(1 / scale), mc, btn, down)) {
                needUpdateView = true;
                return true;
            }
        }

        // ?      -      ?
        if (down) {
            mouse_map_pos = s2m(gui.mouse_pos.mul(1 / scale).add(viewoffset(scaled_size, this.mc).inverse()));
            if (mouse_map_pos != null)
                SendMapClick(btn);
            needUpdateView = true;
            return true;
        }

        return false;
    }

    private void SendMapClick(int btn) {
        last_time_mouse_send = System.currentTimeMillis();
        SEND_map_click(place_obj != null ? 0 : (mouse_in_object != null ? mouse_in_object.id : 0),
                place_obj != null ? mouse_tile_coord.x : mouse_map_pos.x,
                place_obj != null ? mouse_tile_coord.y : mouse_map_pos.y, gui.mouse_pos.x, gui.mouse_pos.y, btn,
                Input.GetKeyState());
    }

    // CAMERAS ==============================================================

    public static class Camera {
        Coord last_mouse_pos = Coord.z;

        public void setpos(GUI_Map mv, Obj player, Coord sz) {
        }

        public boolean DoMouseBtn(GUI_Map mv, Coord sc, Coord mc, int button, boolean down) {
            return (false);
        }

        public void update(GUI_Map mv) {
            if (!last_mouse_pos.equals(mv.gui.mouse_pos)) {
                last_mouse_pos = new Coord(mv.gui.mouse_pos.mul(1 / scale));
                mouse_move(mv, last_mouse_pos);
            }
        }

        public void mouse_move(GUI_Map mv, Coord sc) {
        }

        public void moved(GUI_Map mv) {
        }

        //      public static void borderize(GUI_Map mv, Obj player, Coord sz, Coord border) {}

        public void reset() {
        }

        public void scaled(GUI_Map mv, float old_scale) {
        }
    }

    private static abstract class DragCam extends Camera {
        Coord begin_drag, mo;
        boolean dragging = false;

        public boolean DoMouseBtn(GUI_Map mv, Coord sc, Coord mc, int button, boolean down) {
            if (button == Input.MB_MIDDLE)
                if (down) {
                    mv.gui.SetMouseGrab(mv);
                    begin_drag = sc;
                    mo = null;
                    dragging = true;
                    return (true);
                } else {
                    if (dragging) {
                        mv.gui.SetMouseGrab(null);
                        dragging = false;
                        if (mo == null) {
                            mv.mc = mc;
                            moved(mv);
                        }
                        return (true);
                    }
                }
            return (false);
        }

        public void mouse_move(GUI_Map mv, Coord sc) {
            if (dragging) {
                Coord off = sc.add(begin_drag.inverse());
                if ((mo == null) && (off.dist(Coord.z) > 5))
                    mo = mv.mc;
                if (mo != null) {
                    mv.mc = mo.add(s2m(off).inverse());
                    moved(mv);
                }
                needUpdateView = true;
            }
        }

    }

    static class FixedCam extends DragCam {
        private Coord off = Coord.z;
        private boolean setoff = false;

        public void setpos(GUI_Map mv, Obj player, Coord sz) {
            if (setoff) {
                off = mv.mc.add(player.getpos().inverse());
                setoff = false;
            }
            mv.mc = player.getpos().add(off);
        }

        public void moved(GUI_Map mv) {
            setoff = true;
        }

        public void reset() {
            off = Coord.z;
            needUpdateView = true;
        }

        public void scaled(GUI_Map mv, float old_scale) {
            Coord d2 = mv.size.div(2);
            Coord old = s2m(d2.mul(1 / old_scale));
            Coord ns = s2m(d2.mul(1 / scale));
            Coord ds = ns.sub(old);
            Coord m1 = s2m(d2);
            Coord m2 = s2m(mv.gui.mouse_pos);
            Coord mmc = m1.sub(m2);
            float dx = (float) mmc.x / (float) m1.x;
            float dy = (float) mmc.y / (float) m1.y;
            ds = ds.mul(dx, dy);
            mv.mc = mv.mc.add(ds);
            setoff = true;
        }
    }

    // CAMERAS END ==============================================================

    public void set_place(String name) {
        if (name.equals("none"))
            place_obj = null;
        else {
            place_obj = new Obj(mouse_tile_coord);
            place_obj.setattr(new Drawable(place_obj, name));
        }
    }

    /*   2x2:
     *    |2,   -2|
     *    |1,    1|
     */
    public static Coord m2s(Coord c) {
        return (new Coord((c.x * 2) - (c.y * 2), c.x + c.y));
    }

    /*  22:
     *    |0.25,   0.5|
     *    |-0.25,   0.5|
     */
    public static Coord s2m(Coord c) {
        return (new Coord((c.x / 4) + (c.y / 2), (c.y / 2) - (c.x / 4)));
    }

    public static Coord tilify(Coord c) {
        c = c.div(TILE_SIZE);
        c = c.mul(TILE_SIZE);
        c = c.add(TILE_SIZE / 2);
        return (c);
    }

    static Coord viewoffset(Coord sz, Coord vc) {
        return (m2s(vc).inverse().add(sz.div(2)));
    }

    public void set_camera(String name) {
        Class<? extends Camera> ct = cameras.get(name);
        try {
            try {
                camera = ct.newInstance();
            } catch (IllegalAccessException e) {
            }
        } catch (InstantiationException e) {
            throw (new Error(e));
        }
        camera = new FixedCam();
    }

    private Obj get_player() {
        return ObjCache.get(Player.CharID);
    }

    private Coord my_coord() {
        Obj p = get_player();
        if (p != null)
            return p.getpos();
        return Coord.z;
    }

    public void DrawTiles() {
        int x, y, i;
        int stw, sth;
        Coord oc, tc, ctc, sc;

        RenderedTiles = 0;
        Render2D.ChangeColor();
        Sprite.setStaticColor();

        //   ? ?
        stw = (TILE_SIZE * 4) - 2;
        sth = TILE_SIZE * 2;
        // ?  ?
        Coord sz = scaled_size;
        oc = viewoffset(sz, mc);
        //   ? ?
        tc = mc.div(TILE_SIZE);
        tc.x += -(sz.x / (2 * stw)) - (sz.y / (2 * sth)) - 2;
        tc.y += (sz.x / (2 * stw)) - (sz.y / (2 * sth));

        if (needUpdateView) {

            needUpdateView = false;

            for (y = 0; y < (sz.y / sth) + 13; y++) {
                for (x = 0; x < (sz.x / stw) + 3; x++) {
                    for (i = 0; i < 2; i++) {
                        //   
                        ctc = tc.add(new Coord(x + y, y - x + i));
                        // ?  
                        sc = m2s(ctc.mul(TILE_SIZE)).add(oc);
                        sc.x -= TILE_SIZE * 2;
                        //  
                        //    ? 
                        drawtile(ctc, sc);
                    }
                }
            }

            // ?   ? 
            if (Config.tile_grid) {
                for (y = 0; y < (sz.y / sth) + 2; y++) {
                    for (x = 0; x < (sz.x / stw) + 3; x++) {
                        for (i = 0; i < 2; i++) {
                            ctc = tc.add(new Coord(x + y, -x + y + i));
                            sc = m2s(ctc.mul(TILE_SIZE)).add(oc);
                            drawtile_grid(sc);
                        }
                    }
                }
            }

            if (render_claims) {
                Color col;
                for (ClaimPersonal claim : Claims.claims.values()) {

                    if (Player.CharID == claim.owner_id) {
                        col = new Color(0f, 1f, 1f, 0.25f);
                        //                  if (Claims.expand_claim != null)
                        //                     continue;
                    } else
                        col = new Color(1f, 0f, 0f, 0.25f);

                    putClaim(claim, oc, col);
                }

                if (Claims.expand_claim != null) {
                    col = new Color(0f, 0f, 0.8f, 0.17f);

                    putClaim(Claims.expand_claim, oc, col);
                }
            }

            //
            updateVBO();
        }

        Color.white.bind();
        GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
        GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, tile_vbo);
        GL11.glVertexPointer(2, GL11.GL_FLOAT, 16, 0L);
        GL11.glTexCoordPointer(2, GL11.GL_FLOAT, 16, 8L);

        Resource.textures.get("tiles").bind();

        GL11.glDrawArrays(GL11.GL_QUADS, 0, tile_drawCount);

        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
        GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);

        if (render_claims) {
            GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
            GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, claim_vbo);
            GL11.glColorPointer(4, GL11.GL_FLOAT, 24, 0L);
            GL11.glVertexPointer(2, GL11.GL_FLOAT, 24, 16L);
            GL11.glDrawArrays(GL11.GL_QUADS, 0, claim_drawCount);
            GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
        }

        if (Config.tile_grid) {
            GL11.glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
            GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, tileGrid_vbo);
            GL11.glVertexPointer(2, GL11.GL_FLOAT, 0, 0L);
            GL11.glDrawArrays(GL11.GL_LINES, 0, tileGrid_drawCount);
        }

        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
        GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);

    }

    private void putClaim(ClaimPersonal c, Coord oc, Color col) {

        if (claim_vboSize < claim_Offset + 24)
            return;

        Coord lt = m2s(c.lt).mul(TILE_SIZE).add(oc);
        Coord lb = m2s(new Coord(c.lt.x, c.rb.y + 1)).mul(TILE_SIZE).add(oc);
        Coord rt = m2s(new Coord(c.rb.x + 1, c.lt.y)).mul(TILE_SIZE).add(oc);
        Coord rb = m2s(c.rb.add(1, 1)).mul(TILE_SIZE).add(oc);

        putColor(col);
        putPoint(lt);

        putColor(col);
        putPoint(rt);

        putColor(col);
        putPoint(rb);

        putColor(col);
        putPoint(lb);
    }

    private void putColor(Color color) {
        claim_vboUpdate[claim_Offset++] = color.r;
        claim_vboUpdate[claim_Offset++] = color.g;
        claim_vboUpdate[claim_Offset++] = color.b;
        claim_vboUpdate[claim_Offset++] = color.a;
    }

    private void putPoint(Coord point) {
        claim_vboUpdate[claim_Offset++] = point.x;
        claim_vboUpdate[claim_Offset++] = point.y;
    }

    public void PrepareRenderParts() {
        Coord oc = viewoffset(scaled_size, mc);
        render_parts.clear();
        try {
            synchronized (ObjCache.objs) {
                Collection<Obj> os = ObjCache.objs.values();
                for (Obj o : os) {
                    o.prepare_draw(oc);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (place_obj != null) {
            //Coord dc = m2s(place_obj.getpos()).add(oc);
            place_obj.prepare_draw(oc);
        }

    }

    //     ?.
    public boolean CheckDrawCoord(Coord dc) {
        return !(dc.x < -100 || dc.y < -100 || dc.x > Config.getScreenWidth() + 100
                || dc.y > Config.getScreenHeight() + 100);
    }

    public Color get_render_part_color(RenderPart p) {
        // ? ?  -   ? 
        if (p.owner != null) {
            if (p.owner == place_obj)
                return new Color(1.0f, 1.0f, 1.0f, 0.8f);
            else
            // ?    
            if (p.owner == mouse_in_object)
                return new Color(201, 236, 10, 255);
            else
            // ? ? ?   ?
            if (p.owner.shp > 0) {
                float k = (float) p.owner.hp / (float) p.owner.shp;
                return new Color(1.0f, k, k, 1.0f);
            } else {
                return new Color(1.0f, 1.0f, 1.0f, 1.0f);
            }
        } else
            // ? ? ?   ?
            return new Color(1.0f, 1.0f, 1.0f, 1.0f);
    }

    public void DrawObjects() {

        // render all parts
        if (!render_rects) {
            player_rendered = false;
            player_rect = null;
            for (RenderPart p : render_parts) {
                Color col = get_render_part_color(p);

                if (Config.hide_overlapped && !p.ignore_overlap) {
                    if (player_rendered && !p.is_my_player) {
                        if (player_rect.is_intersect(p.screen_coord.x, p.screen_coord.y, p.size.x, p.size.y)) {
                            p.is_overlapped = true;
                            if (col == null)
                                col = new Color(1.0f, 1.0f, 1.0f, OVERLAY_K);
                            else
                                col.a = col.a * OVERLAY_K;
                        }
                    }
                }

                Sprite.setStaticColor(col);

                p.render();

                if (Config.hide_overlapped && (!p.ignore_overlap || p.is_my_player)) {
                    if (p.is_my_player && p.z > 1) {
                        if (!player_rendered)
                            player_rect = new Rect(p.screen_coord, p.size);
                        else
                            player_rect = player_rect.Union(p.screen_coord, p.size);
                        player_rendered = true;
                    }
                }
            }

            mouse_in_object = null;
            ignore_overlapped = false;
            if (MouseInMe()) {
                //  ?? 
                for (int u = render_parts.size() - 1; u >= 0; u--) {
                    RenderPart p = render_parts.get(u);
                    if (p.owner != place_obj && p.owner != null && p.check_hit(gui.mouse_pos.mul(1 / scale))) {
                        mouse_in_object = p.owner;
                        break;
                    }
                }
                if (mouse_in_object == null && Config.hide_overlapped) {
                    ignore_overlapped = true;
                    for (RenderPart p : render_parts) {
                        if (p.is_overlapped && p.owner != place_obj && p.owner != null
                                && p.check_hit(gui.mouse_pos.mul(1 / scale))) {
                            mouse_in_object = p.owner;
                            break;
                        }
                    }
                }
            }

        }
        Sprite.setStaticColor();

        Coord oc = viewoffset(scaled_size, mc);
        //   
        for (Obj o : ObjCache.objs.values()) {
            Coord dc = m2s(o.getpos()).add(oc).mul(scale);
            if (!CheckDrawCoord(dc))
                continue;
            ///////////////
            if (render_rects) {
                Render2D.ChangeColor(Color.red);
                Render2D.Disable2D();
                Render2D.FillRect(dc.add(-10, -40), new Coord(20, 40));
                Render2D.Enable2D();
            }
            ///////////////////-----------------------------------------------
            // 
            String nick = "";
            KinInfo kin = o.getattr(KinInfo.class);
            if (kin != null) {
                nick = kin.name;
            }

            ///////////
            if (Config.debug) {
                nick += " objid=" + o.id;
                nick += " dir=" + o.direction;
                //  ?
                LineMove l = o.getattr(LineMove.class);
                if (l != null) {
                    Render2D.Disable2D();
                    Render2D.ChangeColor(Color.red);
                    Render2D.Line(m2s(o.getpos()).add(oc), m2s(l.get_end()).add(oc), 1f);
                    Render2D.Enable2D();
                    nick += " move";
                }
            }
            if (kin != null) {// || Config.debug) {
                GL11.glPushMatrix();
                GL11.glLoadIdentity();
                Render2D.Text("default", dc.x, dc.y - 10 - Math.round(38 * (scale)), 0, 0, Render2D.Align_Center,
                        nick, Color.white);
                GL11.glPopMatrix();
            }
            //----------------------------------------------------------------

            ///////////////
            //  ? 
            ObjSay say = o.getattr(ObjSay.class);
            if (say != null) {
                String m = say.msg;
                if (m.length() > 32)
                    m = m.substring(0, 31) + "...";
                int w = Render2D.GetTextWidth("default", m) + 15;
                int w1, w2, w3;
                int left_w = 35;
                int bh = getSkin().GetElementSize("baloon_center").y;
                w2 = getSkin().GetElementSize("baloon_center").x;
                if (w < 38)
                    w = 38;
                if (w < left_w + getSkin().GetElementSize("baloon_right").x) {
                    w3 = getSkin().GetElementSize("baloon_right").x;
                    w1 = w - w2 - w3;
                } else {
                    w3 = w - left_w;
                    w1 = left_w - w2;
                }
                int bx = dc.x - w1 - (w2 / 2);
                int by = dc.y - bh - 15 - Math.round(38 * scale);
                GL11.glPushMatrix();
                GL11.glLoadIdentity();
                getSkin().Draw("baloon_left", bx, by, w1, bh);
                getSkin().Draw("baloon_center", bx + w1, by, w2, bh);
                getSkin().Draw("baloon_right", bx + w1 + w2, by, w3, bh);

                Render2D.Text("default", bx, by, w, 27, Render2D.Align_Center, m, Color.white);
                GL11.glPopMatrix();
            }

            //  ? 
            o.render_effects(dc);
        }
    }

    public void DrawFlyText() {
        Sprite.setStaticColor();
        Coord oc = viewoffset(scaled_size, mc);

        for (FlyText.FlyTextItem i : FlyText.items) {
            Coord dc = m2s(i.getpos()).add(oc).mul(scale);
            if (CheckDrawCoord(dc)) {
                GL11.glPushMatrix();
                GL11.glLoadIdentity();
                i.Render(dc);
                GL11.glPopMatrix();
            }
        }
    }

    public void drawtile(Coord tc, Coord sc) {
        Sprite s = MapCache.getground(tc);
        if (s != null) {
            s.draw_map_vbo(sc);
            RenderedTiles++;
        }

        Sprite[] ss = MapCache.gettrans(tc);
        if (ss != null)
            for (Sprite s1 : ss) {
                if (s1 != null) {
                    s1.draw_map_vbo(sc);
                    RenderedTiles++;
                }
            }
    }

    public void drawtile_grid(Coord sc) {
        if (tileGrid_vboSize < tileGrid_Offset + 16)
            return;
        Coord c2 = sc.add(m2s(new Coord(0, TILE_SIZE)));
        Coord c4 = sc.add(m2s(new Coord(TILE_SIZE, 0)));

        putLine(c2, sc);
        putLine(sc.add(1, 0), c4.add(1, 0));
    }

    private void putLine(Coord v1, Coord v2) {
        tileGrid_vboUpdate[tileGrid_Offset++] = v1.x;
        tileGrid_vboUpdate[tileGrid_Offset++] = v1.y;

        tileGrid_vboUpdate[tileGrid_Offset++] = v2.x;
        tileGrid_vboUpdate[tileGrid_Offset++] = v2.y;
    }

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    /* * * * * * * * * * * * * * * * * * *       * * * * * * * * * * * * * * * * * */
    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    //   private BufferedImage base_light_tex = null;      // ? ?,    ?
    //   private Sprite current_light_layer = null;

    //   private void ChangeCurrenLightColor(java.awt.Color light) {
    //      base_light_tex = new BufferedImage(Config.getScreenWidth(), Config.getScreenHeight(), BufferedImage.TYPE_INT_ARGB);
    //      Graphics g = base_light_tex.createGraphics();
    //      g.setColor(light);
    //      g.clearRect(0, 0, base_light_tex.getWidth(), base_light_tex.getWidth());
    //   }
    //   
    private void DrawLight(Coord screenCoord, int light_lvl, int radius) {
        Sprite s = new Sprite("light");
        s.draw(screenCoord.x - radius / 2, 768 - screenCoord.y - radius / 2, radius, radius);
        //      BufferedImage img = new BufferedImage(radius * 2 + 1, radius * 2 + 1, BufferedImage.TYPE_INT_ARGB);
        //      for (int x = 0; x < radius * 2; x++)
        //         for (int y = 0; y < radius * 2; y++) {
        //            int cr = (int)Math.sqrt(Math.pow(x - radius, 2) + Math.pow(y - radius, 2));
        //            if (cr < radius) {
        //               if (x > 0 && y > 0 && x < img.getWidth() && y < img.getHeight()) {
        //                  img.setRGB(x, y, new java.awt.Color(55, 55, 55,  128).getRGB());
        //               }
        //            }
        //            else
        //            {
        //               img.setRGB(x, y, 0);
        //            } 
        //            
        //         }
        //      try {
        //         new Sprite(org.newdawn.slick.util.BufferedImageUtil.getTexture("", img)).draw(screenCoord);
        //      } catch (Exception e) {
        //         e.printStackTrace();
        //      }
    }

    public static int LightMap = 0;

    public void DoCreate() {
        IntBuffer tt = BufferUtils.createIntBuffer(1);
        GL11.glGenTextures(tt);
        LightMap = tt.get(0);

        GL11.glBindTexture(GL11.GL_TEXTURE_2D, LightMap);
        ByteBuffer bb = BufferUtils.createByteBuffer(1024 * 1024 * 4);
        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, 1024, 1024, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE,
                bb);
        GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
        GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
        Render2D.CheckError();
    }

    boolean first = true;
    int myFBOId;

    public void CreateLightMap() {

        //Coord screen_size = new Coord(Config.getScreenWidth(), Config.getScreenHeight());
        //Coord screen_coord = new Coord(GUI.map.mc).sub(screen_size.div(2));
        List<Coord> lst = new ArrayList<Coord>();

        for (RenderPart p : render_parts) {
            Drawable d = p.owner.getattr(Drawable.class);
            if (d != null) {
                if (d.name.contains("fir")) {
                    lst.add(p.dc);
                }
                if (d.name.contains("player")) {
                    lst.add(p.dc);
                }
            }
        }

        //      for (Obj o : ObjCache.objs.values()) {
        //         Drawable d = o.getattr(Drawable.class);
        //         if (d != null) {
        //            if (d.name.contains("tree")) {
        //               if (o.getpos().in_rect(screen_coord, screen_size))
        //                  lst.add(o.getpos());
        //            }
        //         }
        //      }

        if (first) {
            first = false;
            boolean FBOEnabled = GLContext.getCapabilities().GL_EXT_framebuffer_object;
            if (!FBOEnabled)
                Log.info("No FBO");
            myFBOId = EXTFramebufferObject.glGenFramebuffersEXT();
            //LightMap = GL11.glGenTextures();

            EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, myFBOId);
            EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
                    EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, GL11.GL_TEXTURE_2D, LightMap, 0);
            EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
        }

        //ByteBuffer bb = ByteBuffer.allocate(1024 * 1024 * 4);
        //GL11.glReadPixels(0, 0, 1024, 768, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, bb);

        // ? FBO  ?  ?
        EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, myFBOId);
        //      GL11.glPushAttrib(GL11.GL_VIEWPORT_BIT);
        //  ?
        //      GL11.glViewport( 0, 0, 1024, 1024 );
        //      
        // ? 
        //   ?
        GL11.glEnable(GL11.GL_TEXTURE_2D);
        GL11.glClearColor(0.3f, 0.3f, 0.4f, 1.0f);
        GL11.glClear(GL_COLOR_BUFFER_BIT);

        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);

        //  ? ? ?
        for (Coord c : lst)
            DrawLight(c, 100, 100);

        /*GL11.glTranslatef(0, 0, -6f);
        GL11.glBegin(GL11.GL_QUADS);
        GL11.glVertex3f(0, 0, 0);
        GL11.glVertex3f(200, 0, 0);
        GL11.glVertex3f(200, 200, 0);
        GL11.glVertex3f(0, 200, 0);
        GL11.glEnd();*/
        //      GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
        //      GL11.glPopAttrib();

        //      GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
        //      
        //  
        //GL11.glBindTexture(GL11.GL_TEXTURE_2D, LightMap);
        //Render2D.CheckError();

        //    ?  - ? 
        //GL11.glCopyTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, 0, 0, 1024, 1024, 0);
        //GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1024, 1024);
        //Render2D.CheckError();

        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

    }

    public void RenderLightMap() {
        GL11.glBlendFunc(GL11.GL_ZERO, GL11.GL_SRC_COLOR);
        //Log.info("lightmap: "+LightMap);
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, LightMap); //Resource.textures.get("core_skin").getTextureID());

        GL11.glTranslatef(0, 0, 0);
        GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

        float texwidth = 1024;
        float texheight = 1024;

        float newTextureOffsetX = 0 / texwidth;
        float newTextureOffsetY = 0 / texheight;
        float newTextureWidth = 1024 / texwidth;
        float newTextureHeight = 1024 / texheight;

        int w = 1024;
        int h = 1024;

        GL11.glBegin(GL11.GL_QUADS);
        {
            glTexCoord2f(newTextureOffsetX, newTextureOffsetY);
            glVertex2i(0, 0);

            glTexCoord2f(newTextureOffsetX, newTextureOffsetY + newTextureHeight);
            glVertex2i(0, h);

            glTexCoord2f(newTextureOffsetX + newTextureWidth, newTextureOffsetY + newTextureHeight);
            glVertex2i(w, h);

            glTexCoord2f(newTextureOffsetX + newTextureWidth, newTextureOffsetY);
            glVertex2i(w, 0);
        }

        GL11.glEnd();

        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
    }

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    public void DoResolutionChanged() {
        scaled_size = new Coord(Config.getScreenWidth(), Config.getScreenHeight()).mul(1 / scale);
        SetSize(Config.getScreenWidth(), Config.getScreenHeight());
        needUpdateView = true;
    }
}