воскресенье, 6 марта 2011 г.

"Access volation" при загрузке моделей X-формата (DirectX) в Irrlicht 1.7.2

В некоторых случаях можно столкнуться с ошибкой нарушения прав доступа при чтении памяти (access violation), пытаясь загрузить X-модель в Irrlicht 1.7.2.

device->getSceneManager()->getMesh("Models/model.x");

Где возникает ошибка (первая строка здесь - это 1019 строка в CXMeshFileLoader.cpp):

u32* data = new u32[datasize];
for (u32 j=0; j<datasize; ++j)
 data[j]=readInt();
if (dataformat&0x102) // 2nd uv set
{
 mesh.TCoords2.reallocate(mesh.Vertices.size());
 u8* dataptr = (u8*) data;
 const u32 size=((dataformat>>8)&0xf)*sizeof(core::vector2df);
 for (u32 j=0; j<mesh.Vertices.size(); ++j)
 {
  mesh.TCoords2.push_back(*((core::vector2df*)(dataptr)));
  dataptr += size;
 }
}

Почему возникает ошибка: всего указателем data адресуются datasize*4 байт памяти, при загрузке модели может оказаться, что mesh.Vertices.size()*size больше, чем datasize*4 (в моем случае так и было) - отсюда и ошибка.

Что предлагается:

u32* data = new u32[datasize];
for (u32 j=0; j<datasize; ++j)
 data[j]=readInt();
if (dataformat&0x102) // 2nd uv set
{
 mesh.TCoords2.reallocate(mesh.Vertices.size());
 u8* dataptr = (u8*) data;
 const u32 size=((dataformat>>8)&0xf)*sizeof(core::vector2df);
 u32 boundary = (datasize << 2)/size;
 for (u32 j=0; j<mesh.Vertices.size() && j<boundary; ++j)
 {
  mesh.TCoords2.push_back(*((core::vector2df*)(dataptr)));
  dataptr += size;
 }
}

Решение, безусловно не идеальное (что произойдет из-за преждевременного завершения цикла в общем случае?), но для всех моделей, которые мне пришлось загружать оказалось подходящим.

В любом случае в ближайшее время сообщу о найденной проблеме сообществу проекта, а там уже пусть решают.

Успешной разработки!

суббота, 22 января 2011 г.

jQuery Validation Plugin и поля формы с одинаковыми именами

Широко используемый плагин Validation для jQuery имеет одну не совсем приятную особенность: имена полей должны быть уникальными, иначе восприниматься будет только первое из всех полей с одинаковым именем.

Это следует учитывать, создавая, например, формы с переменным количеством однотипных полей. В этом случае проблема легко решается, например, генерацией уникальных имен (например, в качестве постфикса к имени можно использовать текущее время) и заданием одинакового класса.

воскресенье, 19 декабря 2010 г.

ASP.NET MVC 2: Controller.File

Тем, кто решит вернуть пользователю файл с кириллическим именем, следует учесть, что такое имя будет воспринято только Firefox'ом (тестировал на версии 3.6), Chrome (тестировал на версии  8.0) и IE (тестировал на версии 8.0) заменят имя на имя действия контроллера.

В принципе, поведение объяснимо.

Пример.

public ActionResult Plain(string text)
{
   File(text.ToBytes(), "text/plain", "Текст.txt");
}

Файрфокс отобразит в диалоге сохранения файла: "Текст.txt", Хром же, как и Эксплорер, отобразят "Plain.txt".

Как вариант решения может быть использована транслитерация.

Пример.

public static class TranslitExtensions
{
    private static readonly Dictionary<string, string> letters 
        = new Dictionary<string, string>
        {
            {"№", "N"},
            {"а", "a"},
            {"б", "b"},
            {"в", "v"},
            {"г", "g"},
            {"д", "d"},
            {"е", "e"},
            {"ё", "yo"},
            {"ж", "zh"},
            {"з", "z"},
            {"и", "i"},
            {"й", "j"},
            {"к", "k"},
            {"л", "l"},
            {"м", "m"},
            {"н", "n"},
            {"о", "o"},
            {"п", "p"},
            {"р", "r"},
            {"с", "s"},
            {"т", "t"},
            {"у", "u"},
            {"ф", "f"},
            {"х", "h"},
            {"ц", "c"},
            {"ч", "ch"},
            {"ш", "sh"},
            {"щ", "sch"},
            {"ъ", "j"},
            {"ы", "i"},
            {"ь", "j"},
            {"э", "e"},
            {"ю", "yu"},
            {"я", "ya"},
            {"А", "A"},
            {"Б", "B"},
            {"В", "V"},
            {"Г", "G"},
            {"Д", "D"},
            {"Е", "E"},
            {"Ё", "Yo"},
            {"Ж", "Zh"},
            {"З", "Z"},
            {"И", "I"},
            {"Й", "J"},
            {"К", "K"},
            {"Л", "L"},
            {"М", "M"},
            {"Н", "N"},
            {"О", "O"},
            {"П", "P"},
            {"Р", "R"},
            {"С", "S"},
            {"Т", "T"},
            {"У", "U"},
            {"Ф", "F"},
            {"Х", "H"},
            {"Ц", "C"},
            {"Ч", "Ch"},
            {"Ш", "Sh"},
            {"Щ", "Sch"},
            {"Ъ", "J"},
            {"Ы", "I"},
            {"Ь", "J"},
            {"Э", "E"},
            {"Ю", "Yu"},
            {"Я", "Ya"}
        };

    /// <summary>
    /// Performs translation from Russian to Translit.
    /// </summary>
    /// <param name="russian">String in Russian to translate.</param>
    /// <returns>String in Translit.</returns>
    public static string ToTranslit(this string russian)
    {
        var builder = new StringBuilder(russian);

        foreach (var letter in letters)
        {
            builder.Replace(letter.Key, letter.Value);
        }

        return builder.ToString();
    }
}

public ActionResult Plain(string text)
{
   File(text.ToBytes(), "text/plain", "Текст.txt".ToTranslit());
}

четверг, 4 ноября 2010 г.

Упрощение навигации по DOM

Хотелось бы затронуть тему правильной организации DOM, best practices, так сказать. Возможно немного пространно сформулировал, но смысл станет ясен после примера.

Пример. Форма ввода свойств некоторой сущности. Конкретнее: редактирование данных пользователя.



С чем столкнулся на практике:

<form action="#">
    <input id="UserId" type="hidden" />
    <div>
        <label>Имя:<input id="UserName" type="text" /></label>
    </div>
    <div>
        <label>Описание:<input id="UserDescription" type="text" /></label>
    </div>
</form>

Запрос с помощью jQuery выглядит следующим образом:

function GetUser() {
    return {
        id: $("#UserId").val(),
        name: $("#UserName").val(),
        description: $("#UserDescription").val()
    };
}

И казалось бы, все отлично. Если бы не:

  • а если у нас несколько элементов управления для ввода данных о пользователях - конфликт идентификаторов (идентификатор должен быть уникален в пределах страницы)?
  • а если наша сущность называется OurEntityWithVeryVeryReallyVeryLongName и имеет множество полей, представляете себе кошмар в виде id="OurEntityWithVeryVeryReallyVeryLongNameFieldWithLongName1" и тому подобное?
Что предлагаю:

<form class="User" action="#">
    <input class="Id" type="hidden" />
    <div>
        <label>Имя:<input class="Name" type="text" /></label>
    </div>
    <div>
        <label>Описание:<input class="Description" type="text" /></label>
    </div>
</form>

Теперь и запрос с помощью jQuery выглядит иначе:

function GetUser() {
    var user = $(".User");
    return {
        id: $(".Id", user).val(),
        name: $(".Name", user).val(),
        description: $(".Description", user).val()
    };
}

Как по мне, вполне приемлемо, и даже похоже на объектную нотацию ("User.Name").

Возможно где-то в Сети уже есть подобное или лучшее решение, как делают Про я не искал (зря? тогда жду комментариев), сразу решил поделиться пришедшей мыслью. На этом все. Удачной разработки!

вторник, 2 ноября 2010 г.

jQuery: позиционирование элементов

Простая задача - разместить абсолютно позиционированный (в стиле определено: position: absolute) div под элементом ввода (input).

var input = $("input");
var offset = input.offset();

var x = offset.left;
var y = offset.top + input.height();

$("div").offset({
    left: x,
    top: y
});

Вот казалось бы и все. И действительно - работает, но если не учитывать вертикальный скроллинг страницы. Если он больше нуля, то div будет выше элемента ввода ровно на значение вертикального скроллинга.

Окончательное решение далее.

var input = $("input");
var offset = input.offset();

var x = offset.left;
var y = offset.top + input.height() + $(window).scrollTop();

$("div").offset({
    left: x,
    top: y
});

воскресенье, 31 октября 2010 г.

JavaScript: Object Oriented or Not?

Все началось с написания клиентских скриптов для существующего веб-приложения с массивным использованием jQuery и асинхронных запросов (aka ajax).

Используется процедурный подход. Я же за ООП, как за средство эффективного снижения сложности.

Ближе к делу.

Поиск по данной теме сразу же привел меня на сайт Дугласа Крокфорда (см. раздел по JavaScript). Не буду пересказывать - очень советую прочесть его статьи по JavaScript - лучшее что я читал за последнее время.

Теперь поделюсь примерами из собственного опыта.

Пространства имен - то, к чему я очень привык, разрабатывая на C++, и особенно на C#.

var Namespace1 = Namespace1 || {};
Namespace1.Namespace2 = Namespace1.Namespace2 || {};

Приватные поля - то, без чего вообще жить нельзя.

Namespace1.Namespace2.Cat = function (name_) {
    var name = name_;
    this.getName = function () {
        return name;
    };
};

Namespace1.Namespace2.Cat.prototype.Meow = function () {
    alert(this.getName() + " says: meow!");
};

Теперь, если выполнить код:

var cat = new Cat("Bluetooth");
cat.name = "WiFi";
cat.Meow();

То "кот промяукает": "Bluetooth says: meow!", но не "WiFi says: meow!".

На этом пока все, в продолжении обязательно расскажу как я реализую наследование.

четверг, 22 июля 2010 г.

Fluent NHibernate и in-memory SQLite база данных

Недавно пришлось писать юнит-тесты для подсистемы доступа к данным, использующей Fluent NHibernate. Для тестов было решено использовать in-memory базу данных SQLite.

Все бы хорошо, да вот проблема - при попытке сохранения данных (ISession.SaveOrUpdate) вылетает исключение "...no such table...". При этом использовалась утилита SchemaExport, так что с созданием таблиц все должно быть в порядке (т. е. это не этот случай).

Так в чем же дело, почему "...no such table..." при попытке "INSERT..."? Не буду много писать, лучше дам ссылку - тут и описание проблемы и одно из ее решений.