From 7790bd6c2c44f32df3859a862f0f9fe71156f3a3 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 15 Aug 2014 13:59:28 +0200 Subject: [PATCH] Implement RGSS2 Tilemap class (TilemapVX) --- binding-mri/binding-mri.cpp | 4 +- binding-mri/binding-util.h | 10 +- binding-mri/tilemapvx-binding.cpp | 158 ++++++++ mkxp.pro | 15 +- shader/tilemapvx.vert | 33 ++ src/autotilesvx.cpp | 269 +++++++++++++ src/shader.cpp | 16 + src/shader.h | 13 + src/tileatlasvx.cpp | 635 ++++++++++++++++++++++++++++++ src/tileatlasvx.h | 67 ++++ src/tilemapvx.cpp | 515 ++++++++++++++++++++++++ src/tilemapvx.h | 71 ++++ 12 files changed, 1797 insertions(+), 9 deletions(-) create mode 100644 binding-mri/tilemapvx-binding.cpp create mode 100644 shader/tilemapvx.vert create mode 100644 src/autotilesvx.cpp create mode 100644 src/tileatlasvx.cpp create mode 100644 src/tileatlasvx.h create mode 100644 src/tilemapvx.cpp create mode 100644 src/tilemapvx.h diff --git a/binding-mri/binding-mri.cpp b/binding-mri/binding-mri.cpp index 1be0289..63d684f 100644 --- a/binding-mri/binding-mri.cpp +++ b/binding-mri/binding-mri.cpp @@ -61,6 +61,7 @@ void tilemapBindingInit(); #ifdef RGSS2 void windowVXBindingInit(); +void tilemapVXBindingInit(); #endif void inputBindingInit(); @@ -87,12 +88,13 @@ static void mriBindingInit() spriteBindingInit(); viewportBindingInit(); planeBindingInit(); - tilemapBindingInit(); #ifdef RGSS2 windowVXBindingInit(); + tilemapVXBindingInit(); #else windowBindingInit(); + tilemapBindingInit(); #endif inputBindingInit(); diff --git a/binding-mri/binding-util.h b/binding-mri/binding-util.h index 06edad7..2f40366 100644 --- a/binding-mri/binding-util.h +++ b/binding-mri/binding-util.h @@ -126,9 +126,10 @@ setPrivateData(VALUE self, void *p) } inline VALUE -wrapObject(void *p, const rb_data_type_struct &type) +wrapObject(void *p, const rb_data_type_struct &type, + VALUE underKlass = rb_cObject) { - VALUE klass = rb_const_get(rb_cObject, rb_intern(type.wrap_struct_name)); + VALUE klass = rb_const_get(underKlass, rb_intern(type.wrap_struct_name)); VALUE obj = rb_obj_alloc(klass); setPrivateData(obj, p); @@ -138,9 +139,10 @@ wrapObject(void *p, const rb_data_type_struct &type) inline VALUE wrapProperty(VALUE self, void *prop, const char *iv, - const rb_data_type_struct &type) + const rb_data_type_struct &type, + VALUE underKlass = rb_cObject) { - VALUE propObj = wrapObject(prop, type); + VALUE propObj = wrapObject(prop, type, underKlass); rb_iv_set(self, iv, propObj); diff --git a/binding-mri/tilemapvx-binding.cpp b/binding-mri/tilemapvx-binding.cpp new file mode 100644 index 0000000..5229f7f --- /dev/null +++ b/binding-mri/tilemapvx-binding.cpp @@ -0,0 +1,158 @@ +/* +** tilemapvx-binding.cpp +** +** This file is part of mkxp. +** +** Copyright (C) 2014 Jonas Kulla +** +** mkxp 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, either version 2 of the License, or +** (at your option) any later version. +** +** mkxp 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 mkxp. If not, see . +*/ + +#include "tilemapvx.h" +#include "viewport.h" +#include "bitmap.h" +#include "table.h" + +#include "disposable-binding.h" +#include "binding-util.h" +#include "binding-types.h" + +DEF_TYPE(TilemapVX); +rb_data_type_struct BitmapArrayType; + +RB_METHOD(tilemapVXInitialize) +{ + TilemapVX *t; + + /* Get parameters */ + VALUE viewportObj = Qnil; + Viewport *viewport = 0; + + rb_get_args(argc, argv, "|o", &viewportObj RB_ARG_END); + + if (!NIL_P(viewportObj)) + viewport = getPrivateDataCheck(viewportObj, ViewportType); + + /* Construct object */ + t = new TilemapVX(viewport); + + setPrivateData(self, t); + + rb_iv_set(self, "viewport", viewportObj); + + wrapProperty(self, &t->getBitmapArray(), "bitmap_array", BitmapArrayType, + rb_const_get(rb_cObject, rb_intern("Tilemap"))); + + VALUE autotilesObj = rb_iv_get(self, "bitmap_array"); + + VALUE ary = rb_ary_new2(7); + for (int i = 0; i < 7; ++i) + rb_ary_push(ary, Qnil); + + rb_iv_set(autotilesObj, "array", ary); + + return self; +} + +RB_METHOD(tilemapVXGetBitmapArray) +{ + RB_UNUSED_PARAM; + + return rb_iv_get(self, "bitmap_array"); +} + +RB_METHOD(tilemapVXUpdate) +{ + RB_UNUSED_PARAM; + + TilemapVX *t = getPrivateData(self); + + t->update(); + + return Qnil; +} + +DEF_PROP_OBJ_NIL(TilemapVX, Viewport, Viewport, "viewport") + +DEF_PROP_OBJ(TilemapVX, Table, MapData, "map_data") +DEF_PROP_OBJ(TilemapVX, Table, FlashData, "flash_data") +DEF_PROP_OBJ(TilemapVX, Table, Flags, "flags") + +DEF_PROP_B(TilemapVX, Visible) + +DEF_PROP_I(TilemapVX, OX) +DEF_PROP_I(TilemapVX, OY) + +RB_METHOD(tilemapVXBitmapsSet) +{ + TilemapVX::BitmapArray *a = getPrivateData(self); + + int i; + VALUE bitmapObj; + + rb_get_args(argc, argv, "io", &i, &bitmapObj RB_ARG_END); + + Bitmap *bitmap = getPrivateDataCheck(bitmapObj, BitmapType); + + a->set(i, bitmap); + + VALUE ary = rb_iv_get(self, "array"); + rb_ary_store(ary, i, bitmapObj); + + return self; +} + +RB_METHOD(tilemapVXBitmapsGet) +{ + int i; + rb_get_args (argc, argv, "i", &i RB_ARG_END); + + if (i < 0 || i > 6) + return Qnil; + + VALUE ary = rb_iv_get(self, "array"); + + return rb_ary_entry(ary, i); +} + +void +tilemapVXBindingInit() +{ + initType(TilemapVXType, "Tilemap", freeInstance); + + VALUE klass = rb_define_class("Tilemap", rb_cObject); + rb_define_alloc_func(klass, classAllocate<&TilemapVXType>); + + disposableBindingInit(klass); + + _rb_define_method(klass, "initialize", tilemapVXInitialize); + _rb_define_method(klass, "bitmaps", tilemapVXGetBitmapArray); + _rb_define_method(klass, "update", tilemapVXUpdate); + + INIT_PROP_BIND( TilemapVX, Viewport, "viewport" ); + INIT_PROP_BIND( TilemapVX, MapData, "map_data" ); + INIT_PROP_BIND( TilemapVX, FlashData, "flash_data" ); + INIT_PROP_BIND( TilemapVX, Flags, "flags" ); + INIT_PROP_BIND( TilemapVX, Visible, "visible" ); + INIT_PROP_BIND( TilemapVX, OX, "ox" ); + INIT_PROP_BIND( TilemapVX, OY, "oy" ); + + initType(BitmapArrayType, "BitmapArray", 0); + + klass = rb_define_class_under(klass, "BitmapArray", rb_cObject); + rb_define_alloc_func(klass, classAllocate<&BitmapArrayType>); + + _rb_define_method(klass, "[]=", tilemapVXBitmapsSet); + _rb_define_method(klass, "[]", tilemapVXBitmapsGet); +} diff --git a/mkxp.pro b/mkxp.pro index 2695f4b..2c082fc 100644 --- a/mkxp.pro +++ b/mkxp.pro @@ -197,17 +197,23 @@ EMBED = \ RGSS2 { HEADERS += \ - src/windowvx.h + src/windowvx.h \ + src/tilemapvx.h \ + src/tileatlasvx.h SOURCES += \ src/vorbissource.cpp \ - src/windowvx.cpp + src/windowvx.cpp \ + src/tilemapvx.cpp \ + src/tileatlasvx.cpp \ + src/autotilesvx.cpp EMBED += \ shader/blur.frag \ shader/blurH.vert \ shader/blurV.vert \ - shader/simpleMatrix.vert + shader/simpleMatrix.vert \ + shader/tilemapvx.vert } MIDI { @@ -318,7 +324,8 @@ BINDING_MRI { RGSS2 { SOURCES += \ - binding-mri/windowvx-binding.cpp + binding-mri/windowvx-binding.cpp \ + binding-mri/tilemapvx-binding.cpp } } diff --git a/shader/tilemapvx.vert b/shader/tilemapvx.vert new file mode 100644 index 0000000..5ad87c2 --- /dev/null +++ b/shader/tilemapvx.vert @@ -0,0 +1,33 @@ + +uniform mat4 projMat; + +uniform vec2 texSizeInv; +uniform vec2 translation; + +uniform vec2 aniOffset; + +attribute vec2 position; +attribute vec2 texCoord; + +varying vec2 v_texCoord; + +const vec2 atAreaA = vec2(9.0*32.0, 12.0*32.0); +const float atAreaCX = 12.0*32.0; +const float atAreaCW = 4.0*32.0; + +void main() +{ + vec2 tex = texCoord; + + /* Type A autotiles shift horizontally */ + if (tex.x <= atAreaA.x && tex.y <= atAreaA.y) + tex.x += aniOffset.x; + + /* Type C autotiles shift vertically */ + if (tex.x >= atAreaCX && tex.x <= (atAreaCX+atAreaCW) && tex.y <= atAreaA.y) + tex.y += aniOffset.y; + + gl_Position = projMat * vec4(position + translation, 0, 1); + + v_texCoord = tex * texSizeInv; +} diff --git a/src/autotilesvx.cpp b/src/autotilesvx.cpp new file mode 100644 index 0000000..f40bdd3 --- /dev/null +++ b/src/autotilesvx.cpp @@ -0,0 +1,269 @@ +struct StaticRect { float x, y, w, h; }; + +extern const StaticRect autotileVXRectsA[] = +{ + { 32.5, 64.5, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 0, 64.5, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 0, 64.5, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 0, 64.5, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 0, 64.5, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 48.5, 64.5, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 48.5, 48.5, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 48.5, 64.5, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 48.5, 48.5, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 48.5, 64.5, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 48.5, 48.5, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 48.5, 64.5, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 48.5, 48.5, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 32.5, 80.5, 15, 15 }, + { 16, 80.5, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 32.5, 80.5, 15, 15 }, + { 16, 80.5, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 80.5, 15, 15 }, + { 16, 80.5, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 80.5, 15, 15 }, + { 16, 80.5, 15, 15 }, + { 0, 64.5, 15, 15 }, + { 48.5, 64.5, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 48.5, 48.5, 15, 15 }, + { 32.5, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 32.5, 80.5, 15, 15 }, + { 16, 80.5, 15, 15 }, + { 0, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 0, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 32.5, 15, 15 }, + { 48.5, 32.5, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 48.5, 48.5, 15, 15 }, + { 32.5, 32.5, 15, 15 }, + { 48.5, 32.5, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 48.5, 48.5, 15, 15 }, + { 32.5, 64.5, 15, 15 }, + { 48.5, 64.5, 15, 15 }, + { 32.5, 80.5, 15, 15 }, + { 48.5, 80.5, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 48.5, 64.5, 15, 15 }, + { 32.5, 80.5, 15, 15 }, + { 48.5, 80.5, 15, 15 }, + { 0, 64.5, 15, 15 }, + { 16, 64.5, 15, 15 }, + { 0, 80.5, 15, 15 }, + { 16, 80.5, 15, 15 }, + { 0, 64.5, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 0, 80.5, 15, 15 }, + { 16, 80.5, 15, 15 }, + { 0, 32.5, 15, 15 }, + { 48.5, 32.5, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 48.5, 48.5, 15, 15 }, + { 0, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 0, 80.5, 15, 15 }, + { 16, 80.5, 15, 15 }, + { 0, 64.5, 15, 15 }, + { 48.5, 64.5, 15, 15 }, + { 0, 80.5, 15, 15 }, + { 48.5, 80.5, 15, 15 }, + { 32.5, 32.5, 15, 15 }, + { 48.5, 32.5, 15, 15 }, + { 32.5, 80.5, 15, 15 }, + { 48.5, 80.5, 15, 15 }, + { 0, 32.5, 15, 15 }, + { 48.5, 32.5, 15, 15 }, + { 0, 80.5, 15, 15 }, + { 48.5, 80.5, 15, 15 }, + { 0, 0, 15, 15 }, + { 16, 0, 15, 15 }, + { 0, 16, 15, 15 }, + { 16, 16, 15, 15 } +}; + +extern const int autotileVXRectsAN = sizeof(autotileVXRectsA) / sizeof(autotileVXRectsA[0]); + +extern const StaticRect autotileVXRectsB[] = +{ + { 32.5, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 16, 16, 15, 15 }, + { 0, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 0, 16, 15, 15 }, + { 16, 16, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 16, 0, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 16, 16, 15, 15 }, + { 0, 0, 15, 15 }, + { 16, 0, 15, 15 }, + { 0, 16, 15, 15 }, + { 16, 16, 15, 15 }, + { 32.5, 32.5, 15, 15 }, + { 48.5, 32.5, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 0, 32.5, 15, 15 }, + { 48.5, 32.5, 15, 15 }, + { 0, 16, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 16, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 0, 0, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 0, 16, 15, 15 }, + { 48.5, 16, 15, 15 }, + { 32.5, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 0, 32.5, 15, 15 }, + { 16, 32.5, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 16, 0, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 0, 0, 15, 15 }, + { 16, 0, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 16, 48.5, 15, 15 }, + { 32.5, 32.5, 15, 15 }, + { 48.5, 32.5, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 48.5, 48.5, 15, 15 }, + { 0, 32.5, 15, 15 }, + { 48.5, 32.5, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 48.5, 48.5, 15, 15 }, + { 32.5, 0, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 32.5, 48.5, 15, 15 }, + { 48.5, 48.5, 15, 15 }, + { 0, 0, 15, 15 }, + { 48.5, 0, 15, 15 }, + { 0, 48.5, 15, 15 }, + { 48.5, 48.5, 15, 15 } +}; + +extern const int autotileVXRectsBN = sizeof(autotileVXRectsB) / sizeof(autotileVXRectsB[0]); diff --git a/src/shader.cpp b/src/shader.cpp index 428d0d7..4db3095 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -48,6 +48,7 @@ #include "../simpleMatrix.vert.xxd" #include "../blurH.vert.xxd" #include "../blurV.vert.xxd" +#include "../tilemapvx.vert.xxd" #endif @@ -535,6 +536,21 @@ BlurShader::VPass::VPass() ShaderBase::init(); } + +TilemapVXShader::TilemapVXShader() +{ + INIT_SHADER(tilemapvx, simple, TilemapVXShader); + + ShaderBase::init(); + + GET_U(aniOffset); +} + +void TilemapVXShader::setAniOffset(const Vec2 &value) +{ + gl.Uniform2f(u_aniOffset, value.x, value.y); +} + #endif diff --git a/src/shader.h b/src/shader.h index b293397..8dfb387 100644 --- a/src/shader.h +++ b/src/shader.h @@ -243,6 +243,18 @@ struct BlurShader HPass pass1; VPass pass2; }; + +class TilemapVXShader : public ShaderBase +{ +public: + TilemapVXShader(); + + void setAniOffset(const Vec2 &value); + +private: + GLint u_aniOffset; +}; + #endif /* Bitmap blit */ @@ -280,6 +292,7 @@ struct ShaderSet #ifdef RGSS2 SimpleMatrixShader simpleMatrix; BlurShader blur; + TilemapVXShader tilemapVX; #endif }; diff --git a/src/tileatlasvx.cpp b/src/tileatlasvx.cpp new file mode 100644 index 0000000..afb705e --- /dev/null +++ b/src/tileatlasvx.cpp @@ -0,0 +1,635 @@ +/* +** tileatlasvx.cpp +** +** This file is part of mkxp. +** +** Copyright (C) 2014 Jonas Kulla +** +** mkxp 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, either version 2 of the License, or +** (at your option) any later version. +** +** mkxp 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 mkxp. If not, see . +*/ + +#include "tileatlasvx.h" + +#include "bitmap.h" +#include "table.h" +#include "etc-internal.h" +#include "gl-util.h" +#include "gl-meta.h" +#include "sharedstate.h" +#include "glstate.h" +#include "texpool.h" +#include "util.h" + +#include +#include + +/* Regular autotile patterns */ +extern const StaticRect autotileVXRectsA[]; +extern const int autotileVXRectsAN; + +/* Wall autotile patterns */ +extern const StaticRect autotileVXRectsB[]; +extern const int autotileVXRectsBN; + +static const StaticRect autotileVXRectsC[] = +{ + { 32.5, 0.5, 15, 31 }, + { 16.5, 0.5, 15, 31 }, + { 0.0, 0.5, 15, 31 }, + { 16.5, 0.5, 15, 31 }, + { 32.5, 0.5, 15, 31 }, + { 48.5, 0.5, 15, 31 }, + { 0.0, 0.5, 15, 31 }, + { 48.5, 0.5, 15, 31 } +}; + +static elementsN(autotileVXRectsC); + +namespace TileAtlasVX +{ + +static int +wrap(int value, int range) +{ + int res = value % range; + return res < 0 ? res + range : res; +} + +static int16_t +tableGetWrapped(const Table &t, int x, int y, int z = 0) +{ + return t.at(wrap(x, t.xSize()), + wrap(y, t.ySize()), + z); +} + +static int16_t +tableGetSafe(const Table *t, int x) +{ + if (!t) + return 0; + + if (x < 0 || x >= t->xSize()) + return 0; + + return t->at(x); +} + +/* All below constants are in tiles (= 32 pixels) */ + +struct Size +{ + int w, h; + + Size(int w, int h) + : w(w), h(h) + {} +}; + +static const Size bmSizes[BM_COUNT] = +{ + Size(16, 12), /* A1 */ + Size(16, 12), /* A2 */ + Size(16, 8), /* A3 */ + Size(16, 15), /* A4 */ + Size( 8, 16), /* A5 */ + Size(16, 16), /* B */ + Size(16, 16), /* C */ + Size(16, 16), /* D */ + Size(16, 16), /* E */ +}; + +static const Size atArea(16, 13); + +static const Vec2i freeArea(8, 48); + +static const Vec2i CDEArea(16, 0); + +struct Blit +{ + IntRect src; + Vec2i dst; + + Blit(int srcX, int srcY, int w, int h, int dstX, int dstY) + : src(srcX, srcY, w, h), + dst(dstX, dstY) + {} + + Blit(int srcX, int srcY, const Size &size, int dstX, int dstY) + : src(srcX, srcY, size.w, size.h), + dst(dstX, dstY) + {} +}; + +static const Blit blitsA1[] = +{ + /* Animated A autotiles */ + Blit(0, 0, 6, 12, 0, 0), + Blit(8, 0, 6, 12, 6, 0), + /* Unanimated A autotiles */ + Blit(6, 0, 2, 6, freeArea.x, freeArea.y), + /* C autotiles */ + Blit(14, 0, 2, 6, 12, 0), + Blit(6, 6, 2, 6, 14, 0), + Blit(14, 6, 2, 6, 12, 6) +}; + +static const Blit blitsA2[] = +{ + Blit(0, 0, bmSizes[BM_A2], 0, atArea.h) +}; + +static const Blit blitsA3[] = +{ + Blit(0, 0, bmSizes[BM_A3], 0, blitsA2[0].dst.y+blitsA2[0].src.h) +}; + +static const Blit blitsA4[] = +{ + Blit(0, 0, bmSizes[BM_A4], 0, blitsA3[0].dst.y+blitsA3[0].src.h) +}; + +static const Blit blitsA5[] = +{ + Blit(0, 0, bmSizes[BM_A5], 0, blitsA4[0].dst.y+blitsA4[0].src.h) +}; + +static const Blit blitsB[] = +{ + Blit(0, 0, bmSizes[BM_B], atArea.w, 0) +}; + +static const Blit blitsC[] = +{ + Blit(0, 0, bmSizes[BM_C], blitsA2[0].src.w, blitsB[0].dst.y+blitsB[0].src.h) +}; + +static const Blit blitsD[] = +{ + Blit(0, 0, bmSizes[BM_D], blitsC[0].dst.x, blitsC[0].dst.y+blitsC[0].src.h) +}; + +static const Blit blitsE[] = +{ + Blit(0, 0, bmSizes[BM_E], blitsD[0].dst.x, blitsD[0].dst.y+blitsD[0].src.h) +}; + +static elementsN(blitsA1); +static elementsN(blitsA2); +static elementsN(blitsA3); +static elementsN(blitsA4); +static elementsN(blitsA5); +static elementsN(blitsB); +static elementsN(blitsC); +static elementsN(blitsD); +static elementsN(blitsE); + +/* 'Waterfall' autotiles atlas origin */ +static const Vec2i AEPartsDst[] = +{ + Vec2i(12, 0), + Vec2i(12, 3), + Vec2i(14, 0), + Vec2i(14, 3), + Vec2i(12, 6), + Vec2i(12, 9) +}; + +static const Vec2i shadowArea(freeArea.x+2, freeArea.y); + +static SDL_Surface* +createShadowSet() +{ + int bpp; + Uint32 rm, gm, bm, am; + + SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, &bpp, &rm, &gm, &bm, &am); + SDL_Surface *surf = SDL_CreateRGBSurface(0, 1*32, 16*32, bpp, rm, gm, bm, am); + + std::vector rects; + SDL_Rect rect = { 0, 0, 16, 16 }; + + for (int val = 0; val < 16; ++val) + { + int origY = val*32; + + /* Top left */ + if (val & (1 << 0)) + { + rect.x = 0; + rect.y = origY; + rects.push_back(rect); + } + + /* Top Right */ + if (val & (1 << 1)) + { + rect.x = 16; + rect.y = origY; + rects.push_back(rect); + } + + /* Bottom left */ + if (val & (1 << 2)) + { + rect.x = 0; + rect.y = origY+16; + rects.push_back(rect); + } + + /* Bottom right */ + if (val & (1 << 3)) + { + rect.x = 16; + rect.y = origY+16; + rects.push_back(rect); + } + } + + /* Fill rects with half opacity black */ + uint32_t color = (0x80808080 & am); + SDL_FillRects(surf, &rects[0], rects.size(), color); + + return surf; +} + +void build(TEXFBO &tf, Bitmap *bitmaps[BM_COUNT]) +{ + assert(tf.width == ATLASVX_W && tf.height == ATLASVX_H); + + GLMeta::blitBegin(tf); + + glState.clearColor.pushSet(Vec4()); + FBO::clear(); + glState.clearColor.pop(); + + SDL_Surface *shadow = createShadowSet(); + TEX::bind(tf.tex); + TEX::uploadSubImage(shadowArea.x*32, shadowArea.y*32, + shadow->w, shadow->h, shadow->pixels, GL_RGBA); + SDL_FreeSurface(shadow); + + Bitmap *bm; +#define EXEC_BLITS(part) \ + if ((bm = bitmaps[BM_##part])) \ + { \ + GLMeta::blitSource(bm->getGLTypes()); \ + for (size_t i = 0; i < blits##part##N; ++i) \ + {\ + IntRect src = blits##part[i].src; \ + src = IntRect(src.x*32, src.y*32, src.w*32, src.h*32); \ + Vec2i dst = blits##part[i].dst; \ + dst = Vec2i(dst.x*32, dst.y*32); \ + GLMeta::blitRectangle(src, dst); \ + } \ + } + + EXEC_BLITS(A1); + EXEC_BLITS(A2); + EXEC_BLITS(A3); + EXEC_BLITS(A4); + EXEC_BLITS(A5); + EXEC_BLITS(B); + EXEC_BLITS(C); + EXEC_BLITS(D); + EXEC_BLITS(E); + +#undef EXEC_BLITS + + GLMeta::blitEnd(); +} + +#define OVER_PLAYER_FLAG (1 << 4) + +static void +atSelectSubPos(FloatRect &pos, int i) +{ + switch (i) + { + case 0: + return; + case 1: + pos.x += 16; + return; + case 2: + pos.y += 16; + return; + case 3: + pos.x += 16; + pos.y += 16; + return; + default: + assert(!"Unreachable"); + } +} + +/* Reference: http://www.tktkgame.com/tkool/memo/vx/tile_id.html */ + +static void +readAutotile(Reader &reader, int patternID, + const Vec2i &orig, int x, int y, + const StaticRect rectSource[], int rectSourceN) +{ + FloatRect tex[4], pos[4]; + + for (int i = 0; i < 4; ++i) + { + assert((patternID*4 + i) < rectSourceN); + + tex[i] = FloatRect(rectSource[patternID*4 + i]); + tex[i].x += orig.x*32; + tex[i].y += orig.y*32; + + pos[i] = FloatRect(x*32, y*32, 16, 16); + atSelectSubPos(pos[i], i); + } + + reader.onQuads4(tex, pos); +} + +static void +readAutotileA(Reader &reader, int patternID, + const Vec2i &orig, int x, int y) +{ + readAutotile(reader, patternID, orig, x, y, + autotileVXRectsA, autotileVXRectsAN); +} + +static void +readAutotileB(Reader &reader, int patternID, + const Vec2i &orig, int x, int y) +{ + if (patternID >= 0x10) + return; + + readAutotile(reader, patternID, orig, x, y, + autotileVXRectsB, autotileVXRectsBN); +} + +static void +readAutotileC(Reader &reader, int patternID, + const Vec2i &orig, int x, int y) +{ + if (patternID > 0x3) + return; + + FloatRect tex[2], pos[2]; + + for (size_t i = 0; i < 2; ++i) + { + tex[i] = autotileVXRectsC[patternID*2+i]; + tex[i].x += orig.x*32; + tex[i].y += orig.y*32; + + pos[i] = FloatRect(x*32, y*32, 16, 32); + pos[i].x += i*16; + } + + reader.onQuads2(tex, pos); +} + +static void +onTileA1(Reader &reader, int16_t tileID, + const int x, const int y) +{ + tileID -= 0x0800; + + int patternID = tileID % 0x30; + int autotileID = tileID / 0x30; + + const Vec2i autotileC(-1, -1); + const Vec2i atOrig[] = + { + Vec2i(0, 0), + Vec2i(0, 3), + Vec2i(freeArea), + Vec2i(freeArea.x, freeArea.y+3), + Vec2i(6, 0), + autotileC, + Vec2i(6, 3), + autotileC, + + Vec2i(0, 6), + autotileC, + Vec2i(0, 9), + autotileC, + Vec2i(6, 6), + autotileC, + Vec2i(6, 9), + autotileC + }; + + const Vec2i orig = atOrig[autotileID]; + + if (orig.x == -1) + { + int cID = (autotileID - 5) / 2; + const Vec2i orig = AEPartsDst[cID]; + + readAutotileC(reader, patternID, orig, x, y); + return; + } + + readAutotileA(reader, patternID, orig, x, y); +} + +static void +onTileA2(Reader &reader, int16_t tileID, + int x, int y) +{ + Vec2i orig = blitsA2[0].dst; + tileID -= 0x0B00; + + int patternID = tileID % 0x30; + int autotileID = tileID / 0x30; + + orig.x += (autotileID % 8) * 2; + orig.y += (autotileID / 8) * 3; + + readAutotileA(reader, patternID, orig, x, y); +} + +static void +onTileA3(Reader &reader, int16_t tileID, + int x, int y) +{ + Vec2i orig = blitsA3[0].dst; + tileID -= 0x1100; + + int patternID = tileID % 0x30; + int autotileID = tileID / 0x30; + + orig.x += (autotileID % 8) * 2; + orig.y += (autotileID / 8) * 2; + + readAutotileB(reader, patternID, orig, x, y); +} + +static void +onTileA4(Reader &reader, int16_t tileID, + int x, int y) +{ + Vec2i orig = blitsA4[0].dst; + tileID -= 0x1700; + + const int offY[] = { 0, 3, 5, 8, 10, 13 }; + + int patternID = tileID % 0x30; + int autotileID = tileID / 0x30; + + int offYI = autotileID / 8; + orig.x += (autotileID % 8) * 2; + orig.y += offY[offYI]; + + if ((offYI % 2) == 0) + readAutotileA(reader, patternID, orig, x, y); + else + readAutotileB(reader, patternID, orig, x, y); +} + +static void +onTileA5(Reader &reader, int16_t tileID, + int x, int y, bool overPlayer) +{ + const Vec2i orig = blitsA5[0].dst; + tileID -= 0x0600; + + int ox = tileID % 0x8; + int oy = tileID / 0x8; + + FloatRect tex((orig.x+ox)*32+0.5, (orig.y+oy)*32+0.5, 31, 31); + FloatRect pos(x*32, y*32, 32, 32); + + reader.onQuads1(tex, pos, overPlayer); +} + +static void +onTileBCDE(Reader &reader, int16_t tileID, + int x, int y, bool overPlayer) +{ + int ox = tileID % 0x8; + int oy = (tileID / 0x8) % 0x10; + int ob = tileID / (0x8*0x10); + + ox += (ob % 2) * 0x8; + oy += (ob / 2) * 0x10; + + FloatRect tex((CDEArea.x+ox)*32+0.5, (CDEArea.y+oy)*32+0.5, 31, 31); + FloatRect pos(x*32, y*32, 32, 32); + + reader.onQuads1(tex, pos, overPlayer); +} + +static void +onTile(Reader &reader, int16_t tileID, + int x, int y, bool overPlayer) +{ + /* B ~ E */ + if (tileID < 0x0400) + { + onTileBCDE(reader, tileID, x, y, overPlayer); + return; + } + + /* A5 */ + if (tileID >= 0x0600 && tileID < 0x0680) + { + onTileA5(reader, tileID, x, y, overPlayer); + return; + } + + if (tileID >= 0x0800 && tileID < 0x0B00) + { + onTileA1(reader, tileID, x, y); + return; + } + + /* A2 */ + if (tileID >= 0x0B00 && tileID < 0x1100) + { + onTileA2(reader, tileID, x, y); + return; + } + + /* A3 */ + if (tileID < 0x1700) + { + onTileA3(reader, tileID, x, y); + return; + } + + /* A4 */ + if (tileID < 0x2000) + { + onTileA4(reader, tileID, x, y); + return; + } +} + +static void +readLayer(Reader &reader, const Table &data, + const Table *flags, int ox, int oy, int w, int h, int z) +{ + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) + { + int16_t tileID = tableGetWrapped(data, x+ox, y+oy, z); + bool overPlayer = tableGetSafe(flags, tileID) & OVER_PLAYER_FLAG; + + if (tileID <= 0) + continue; + + onTile(reader, tileID, x, y, overPlayer); + } +} + +static void +onShadowTile(Reader &reader, int8_t value, + int x, int y) +{ + if (value == 0) + return; + + int oy = value; + + FloatRect tex((shadowArea.x)*32+0.5, (shadowArea.y+oy)*32+0.5, 31, 31); + FloatRect pos(x*32, y*32, 32, 32); + + reader.onQuads1(tex, pos, false); +} + +static void +readShadowLayer(Reader &reader, const Table &data, + int ox, int oy, int w, int h) +{ + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) + { + int16_t value = tableGetWrapped(data, x+ox, y+oy, 3); + onShadowTile(reader, value & 0xF, x, y); + } +} + +void readTiles(Reader &reader, const Table &data, + const Table *flags, int ox, int oy, int w, int h) +{ + for (int i = 0; i < 2; ++i) + readLayer(reader, data, flags, ox, oy, w, h, i); + + readShadowLayer(reader, data, ox, oy, w, h); + + readLayer(reader, data, flags, ox, oy, w, h, 2); +} + +} diff --git a/src/tileatlasvx.h b/src/tileatlasvx.h new file mode 100644 index 0000000..306240d --- /dev/null +++ b/src/tileatlasvx.h @@ -0,0 +1,67 @@ +/* +** tileatlasvx.h +** +** This file is part of mkxp. +** +** Copyright (C) 2014 Jonas Kulla +** +** mkxp 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, either version 2 of the License, or +** (at your option) any later version. +** +** mkxp 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 mkxp. If not, see . +*/ + +#ifndef TILEATLASVX_H +#define TILEATLASVX_H + +#include + +struct FloatRect; +struct TEXFBO; +class Bitmap; +class Table; + +#define ATLASVX_W 1024 +#define ATLASVX_H 2048 + +/* Bitmap indices */ +enum +{ + BM_A1 = 0, + BM_A2 = 1, + BM_A3 = 2, + BM_A4 = 3, + BM_A5 = 4, + BM_B = 5, + BM_C = 6, + BM_D = 7, + BM_E = 8, + + BM_COUNT +}; + +namespace TileAtlasVX +{ +struct Reader +{ + virtual void onQuads1(const FloatRect &t, const FloatRect &p, + bool overPlayer) = 0; + virtual void onQuads2(const FloatRect t[2], const FloatRect p[2]) = 0; + virtual void onQuads4(const FloatRect t[4], const FloatRect p[4]) = 0; +}; + +void build(TEXFBO &tf, Bitmap *bitmaps[BM_COUNT]); + +void readTiles(Reader &reader, const Table &data, + const Table *flags, int ox, int oy, int w, int h); +} + +#endif // TILEATLASVX_H diff --git a/src/tilemapvx.cpp b/src/tilemapvx.cpp new file mode 100644 index 0000000..633a551 --- /dev/null +++ b/src/tilemapvx.cpp @@ -0,0 +1,515 @@ +/* +** tilemapvx.cpp +** +** This file is part of mkxp. +** +** Copyright (C) 2014 Jonas Kulla +** +** mkxp 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, either version 2 of the License, or +** (at your option) any later version. +** +** mkxp 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 mkxp. If not, see . +*/ + +#include "tilemapvx.h" + +#include "tileatlasvx.h" +#include "etc-internal.h" +#include "bitmap.h" +#include "table.h" +#include "viewport.h" +#include "gl-util.h" +#include "sharedstate.h" +#include "glstate.h" +#include "vertex.h" +#include "quad.h" +#include "quadarray.h" +#include "shader.h" + +#include +#include +#include + +/* Map viewport size */ +// FIXME: This will be wrong if resolution is changed +static const int viewpW = 18; +static const int viewpH = 14; + +/* How many tiles are max visible on screen at once */ +static const Vec2i screenTiles(18, 14); + +// FIXME: Implement flash + +struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader +{ + TilemapVX::BitmapArray bitmapsProxy; + Bitmap *bitmaps[BM_COUNT]; + + Table *mapData; + Table *flashData; + Table *flags; + Vec2i offset; + + Vec2i dispPos; + /* Map viewport position */ + Vec2i viewpPos; + Vec2i sceneOffset; + Scene::Geometry sceneGeo; + + std::vector groundVert; + std::vector aboveVert; + + TEXFBO atlas; + VBO::ID vbo; + GLMeta::VAO vao; + + size_t allocQuads; + + size_t groundQuads; + size_t aboveQuads; + + uint16_t frameIdx; + uint8_t aniIdxA; + uint8_t aniIdxC; + Vec2 aniOffset; + + bool atlasDirty; + bool buffersDirty; + bool mapViewportDirty; + + sigc::connection mapDataCon; + sigc::connection flagsCon; + + sigc::connection prepareCon; + sigc::connection bmChangedCons[BM_COUNT]; + sigc::connection bmDisposedCons[BM_COUNT]; + + struct AboveLayer : public ViewportElement + { + TilemapVXPrivate *p; + + AboveLayer(TilemapVXPrivate *p, Viewport *viewport) + : ViewportElement(viewport, 200), + p(p) + {} + + void draw() + { + p->drawAbove(); + } + }; + + AboveLayer above; + + TilemapVXPrivate(Viewport *viewport) + : ViewportElement(viewport), + mapData(0), + flashData(0), + flags(0), + allocQuads(0), + groundQuads(0), + aboveQuads(0), + frameIdx(0), + aniIdxA(0), + aniIdxC(0), + atlasDirty(true), + buffersDirty(false), + mapViewportDirty(false), + above(this, viewport) + { + memset(bitmaps, 0, sizeof(bitmaps)); + + shState->requestAtlasTex(ATLASVX_W, ATLASVX_H, atlas); + + vbo = VBO::gen(); + + GLMeta::vaoFillInVertexData(vao); + vao.vbo = vbo; + vao.ibo = shState->globalIBO().ibo; + GLMeta::vaoInit(vao); + + prepareCon = shState->prepareDraw.connect + (sigc::mem_fun(this, &TilemapVXPrivate::prepare)); + } + + virtual ~TilemapVXPrivate() + { + GLMeta::vaoFini(vao); + VBO::del(vbo); + + shState->releaseAtlasTex(atlas); + + prepareCon.disconnect(); + + mapDataCon.disconnect(); + flagsCon.disconnect(); + + for (size_t i = 0; i < BM_COUNT; ++i) + { + bmChangedCons[i].disconnect(); + bmDisposedCons[i].disconnect(); + } + } + + void invalidateAtlas() + { + atlasDirty = true; + } + + void onBitmapDisposed(int i) + { + bitmaps[i] = 0; + bmChangedCons[i].disconnect(); + bmDisposedCons[i].disconnect(); + + atlasDirty = true; + } + + void invalidateBuffers() + { + buffersDirty = true; + } + + void rebuildAtlas() + { + TileAtlasVX::build(atlas, bitmaps); + } + + void updatePosition() + { + dispPos.x = -(offset.x - viewpPos.x * 32) + sceneOffset.x; + dispPos.y = -(offset.y - viewpPos.y * 32) + sceneOffset.y; + } + + void onGeometryChange(const Scene::Geometry &geo) + { + sceneOffset.x = geo.rect.x - geo.xOrigin; + sceneOffset.y = geo.rect.y - geo.yOrigin; + sceneGeo = geo; + + updatePosition(); + } + + void updateMapViewport() + { + int tileOX, tileOY; + + if (offset.x >= 0) + tileOX = offset.x / 32; + else + tileOX = -(-(offset.x-31) / 32); + + if (offset.y >= 0) + tileOY = offset.y / 32; + else + tileOY = -(-(offset.y-31) / 32); + + bool dirty = false; + + if (tileOX < viewpPos.x || tileOX + screenTiles.x > viewpPos.x + viewpW) + { + viewpPos.x = tileOX; + dirty = true; + } + + if (tileOY < viewpPos.y || tileOY + screenTiles.y > viewpPos.y + viewpH) + { + viewpPos.y = tileOY; + dirty = true; + } + + if (dirty) + { + buffersDirty = true; + } + + updatePosition(); + } + + static size_t quadBytes(size_t quads) + { + return quads * 4 * sizeof(SVertex); + } + + void rebuildBuffers() + { + if (!mapData) + return; + + groundVert.clear(); + aboveVert.clear(); + + TileAtlasVX::readTiles(*this, *mapData, flags, + viewpPos.x, viewpPos.y, viewpW, viewpH); + + groundQuads = groundVert.size() / 4; + aboveQuads = aboveVert.size() / 4; + size_t totalQuads = groundQuads + aboveQuads; + + VBO::bind(vbo); + + if (totalQuads > allocQuads) + { + VBO::allocEmpty(quadBytes(totalQuads), GL_DYNAMIC_DRAW); + allocQuads = totalQuads; + } + + VBO::uploadSubData(0, quadBytes(groundQuads), &groundVert[0]); + VBO::uploadSubData(quadBytes(groundQuads), quadBytes(aboveQuads), &aboveVert[0]); + + VBO::unbind(); + + shState->ensureQuadIBO(totalQuads); + } + + void prepare() + { + if (!mapData) + return; + + if (atlasDirty) + { + rebuildAtlas(); + atlasDirty = false; + } + + if (mapViewportDirty) + { + updateMapViewport(); + mapViewportDirty = false; + } + + if (buffersDirty) + { + rebuildBuffers(); + buffersDirty = false; + } + } + + SVertex *allocVert(std::vector &vec, size_t count) + { + size_t size = vec.size(); + vec.resize(size + count); + + return &vec[size]; + } + + /* SceneElement */ + void draw() + { + TilemapVXShader &shader = shState->shaders().tilemapVX; + shader.bind(); + shader.setTexSize(Vec2i(atlas.width, atlas.height)); + shader.applyViewportProj(); + shader.setTranslation(dispPos); + shader.setAniOffset(aniOffset); + + TEX::bind(atlas.tex); + GLMeta::vaoBind(vao); + + gl.DrawElements(GL_TRIANGLES, groundQuads*6, _GL_INDEX_TYPE, 0); + + GLMeta::vaoUnbind(vao); + } + + void drawAbove() + { + if (aboveQuads == 0) + return; + + SimpleShader &shader = shState->shaders().simple; + shader.bind(); + shader.setTexSize(Vec2i(atlas.width, atlas.height)); + shader.applyViewportProj(); + shader.setTranslation(dispPos); + + TEX::bind(atlas.tex); + GLMeta::vaoBind(vao); + + gl.DrawElements(GL_TRIANGLES, aboveQuads*6, _GL_INDEX_TYPE, + (GLvoid*) (groundQuads*6*sizeof(index_t))); + + GLMeta::vaoUnbind(vao); + } + + /* TileAtlasVX::Reader */ + void onQuads1(const FloatRect &t1, const FloatRect &p1, + bool overPlayer) + { + SVertex *vert; + + if (overPlayer) + vert = allocVert(aboveVert, 4); + else + vert = allocVert(groundVert, 4); + + Quad::setTexPosRect(vert, t1, p1); + } + + void onQuads2(const FloatRect t[2], const FloatRect p[2]) + { + SVertex *vert = allocVert(groundVert, 8); + + Quad::setTexPosRect(&vert[0], t[0], p[0]); + Quad::setTexPosRect(&vert[4], t[1], p[1]); + } + + void onQuads4(const FloatRect t[4], const FloatRect p[4]) + { + SVertex *vert = allocVert(groundVert, 16); + + Quad::setTexPosRect(&vert[ 0], t[0], p[0]); + Quad::setTexPosRect(&vert[ 4], t[1], p[1]); + Quad::setTexPosRect(&vert[ 8], t[2], p[2]); + Quad::setTexPosRect(&vert[12], t[3], p[3]); + } +}; + +void TilemapVX::BitmapArray::set(int i, Bitmap *bitmap) +{ + if (i < 0 || i >= BM_COUNT) + return; + + if (p->bitmaps[i] == bitmap) + return; + + p->bitmaps[i] = bitmap; + p->atlasDirty = true; + + p->bmChangedCons[i].disconnect(); + p->bmChangedCons[i] = bitmap->modified.connect + (sigc::mem_fun(p, &TilemapVXPrivate::invalidateAtlas)); + + p->bmDisposedCons[i].disconnect(); + p->bmDisposedCons[i] = bitmap->wasDisposed.connect + (sigc::bind(sigc::mem_fun(p, &TilemapVXPrivate::onBitmapDisposed), i)); +} + +Bitmap *TilemapVX::BitmapArray::get(int i) const +{ + if (i < 0 || i >= BM_COUNT) + return 0; + + return p->bitmaps[i]; +} + +TilemapVX::TilemapVX(Viewport *viewport) +{ + (void) viewport; + p = new TilemapVXPrivate(viewport); + p->bitmapsProxy.p = p; +} + +TilemapVX::~TilemapVX() +{ + delete p; +} + +void TilemapVX::update() +{ + if (++p->frameIdx >= 30*3*4) + p->frameIdx = 0; + + const uint8_t aniIndicesA[3*4] = + { 0, 1, 2, 1, 0, 1, 2, 1, 0, 1, 2, 1 }; + const uint8_t aniIndicesC[3*4] = + { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2 }; + + p->aniIdxA = aniIndicesA[p->frameIdx / 30]; + p->aniIdxC = aniIndicesC[p->frameIdx / 30]; + + p->aniOffset = Vec2(p->aniIdxA * 2 * 32, p->aniIdxC * 32); +} + +TilemapVX::BitmapArray &TilemapVX::getBitmapArray() const +{ + return p->bitmapsProxy; +} + +DEF_ATTR_RD_SIMPLE(TilemapVX, MapData, Table*, p->mapData) +DEF_ATTR_RD_SIMPLE(TilemapVX, FlashData, Table*, p->flashData) +DEF_ATTR_RD_SIMPLE(TilemapVX, Flags, Table*, p->flags) +DEF_ATTR_RD_SIMPLE(TilemapVX, OX, int, p->offset.x) +DEF_ATTR_RD_SIMPLE(TilemapVX, OY, int, p->offset.y) + +Viewport *TilemapVX::getViewport() const +{ + return p->getViewport(); +} + +bool TilemapVX::getVisible() const +{ + return p->getVisible(); +} + +void TilemapVX::setViewport(Viewport *value) +{ + p->setViewport(value); + p->above.setViewport(value); +} + +void TilemapVX::setMapData(Table *value) +{ + if (p->mapData == value) + return; + + p->mapData = value; + p->buffersDirty = true; + + p->mapDataCon.disconnect(); + p->mapDataCon = value->modified.connect + (sigc::mem_fun(p, &TilemapVXPrivate::invalidateBuffers)); +} + +void TilemapVX::setFlashData(Table *value) +{ + if (p->flashData == value) + return; + + p->flashData = value; +} + +void TilemapVX::setFlags(Table *value) +{ + if (p->flags == value) + return; + + p->flags = value; + p->buffersDirty = true; + + p->flagsCon.disconnect(); + p->flagsCon = value->modified.connect + (sigc::mem_fun(p, &TilemapVXPrivate::invalidateBuffers)); +} + +void TilemapVX::setVisible(bool value) +{ + p->setVisible(value); + p->above.setVisible(value); +} + +void TilemapVX::setOX(int value) +{ + if (p->offset.x == value) + return; + + p->offset.x = value; + p->mapViewportDirty = true; +} + +void TilemapVX::setOY(int value) +{ + if (p->offset.y == value) + return; + + p->offset.y = value; + p->mapViewportDirty = true; +} diff --git a/src/tilemapvx.h b/src/tilemapvx.h new file mode 100644 index 0000000..1a0f313 --- /dev/null +++ b/src/tilemapvx.h @@ -0,0 +1,71 @@ +/* +** tilemapvx.h +** +** This file is part of mkxp. +** +** Copyright (C) 2014 Jonas Kulla +** +** mkxp 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, either version 2 of the License, or +** (at your option) any later version. +** +** mkxp 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 mkxp. If not, see . +*/ + +#ifndef TILEMAPVX_H +#define TILEMAPVX_H + +#include "disposable.h" +#include "util.h" + +class Viewport; +class Bitmap; +class Table; + +struct TilemapVXPrivate; + +class TilemapVX : public Disposable +{ +public: + class BitmapArray + { + public: + void set(int i, Bitmap *bitmap); + Bitmap *get(int i) const; + + private: + BitmapArray() {} + ~BitmapArray() {} + + TilemapVXPrivate *p; + friend class TilemapVX; + friend struct TilemapVXPrivate; + }; + + TilemapVX(Viewport *viewport = 0); + ~TilemapVX(); + + void update(); + + BitmapArray &getBitmapArray() const; + + DECL_ATTR( Viewport, Viewport* ) + DECL_ATTR( MapData, Table* ) + DECL_ATTR( FlashData, Table* ) + DECL_ATTR( Flags, Table* ) + DECL_ATTR( Visible, bool ) + DECL_ATTR( OX, int ) + DECL_ATTR( OY, int ) + +private: + TilemapVXPrivate *p; +}; + +#endif // TILEMAPVX_H