1. C++ / Говнокод #11487

    +19

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    void load_functions(void** functions[], const char* names[], ushort count)
    {
    	for(ushort i=0; i<count; i++)
    		*functions[i]=wglGetProcAddress(names[i]);
    }
    
    ...
    
    void* const glslFunctions[]={&glCreateShader, &glShaderSource, &glCompileShader,
    	&glGetShaderiv, &glGetShaderInfoLog, &glDeleteShader,
    	&glCreateProgram, &glAttachShader, &glLinkProgram, &glGetProgramiv,
    	&glGetProgramInfoLog, &glUseProgram, &glDeleteProgram,
    	&glGetUniformLocation, &glGetActiveUniform, &glBindAttribLocation,
    	&glGenProgramPipelines, &glBindProgramPipeline, &glDeleteProgramPipelines, &glUseProgramStages,
    	&glProgramParameteri, &glGetProgramPipelineiv, &glValidateProgramPipeline, &glGetProgramPipelineInfoLog,
    
    	&glProgramUniform1i, &glProgramUniform2iv, &glProgramUniform3iv, &glProgramUniform4iv,
    	&glProgramUniform1ui, &glProgramUniform2uiv, &glProgramUniform3uiv, &glProgramUniform4uiv,
    	&glProgramUniform1f, &glProgramUniform2fv, &glProgramUniform3fv, &glProgramUniform4fv,
    	&glProgramUniform1d, &glProgramUniform2dv, &glProgramUniform3dv, &glProgramUniform4dv,
    	&glProgramUniformMatrix2fv, &glProgramUniformMatrix3fv, &glProgramUniformMatrix4fv,
    	&glProgramUniformMatrix2x3fv, &glProgramUniformMatrix2x4fv,
    	&glProgramUniformMatrix3x2fv, &glProgramUniformMatrix3x4fv,
    	&glProgramUniformMatrix4x2fv, &glProgramUniformMatrix4x3fv,
    	&glProgramUniformMatrix2dv, &glProgramUniformMatrix3dv, &glProgramUniformMatrix4dv,
    	&glProgramUniformMatrix2x3dv, &glProgramUniformMatrix2x4dv,
    	&glProgramUniformMatrix3x2dv, &glProgramUniformMatrix3x4dv,
    	&glProgramUniformMatrix4x2dv, &glProgramUniformMatrix4x3dv};
    
    const char* glslFuncNames[sizeof(glslFunctions)/sizeof(glslFunctions[0])]=
    	{"glCreateShader", "glShaderSource", "glCompileShader",
    	"glGetShaderiv", "glGetShaderInfoLog", "glDeleteShader",
    	"glCreateProgram", "glAttachShader", "glLinkProgram", "glGetProgramiv",
    	"glGetProgramInfoLog", "glUseProgram", "glDeleteProgram",
    	"glGetUniformLocation", "glGetActiveUniform", "glBindAttribLocation",
    	"glGenProgramPipelines", "glBindProgramPipeline", "glDeleteProgramPipelines", "glUseProgramStages",
    	"glProgramParameteri", "glGetProgramPipelineiv", "glValidateProgramPipeline", "glGetProgramPipelineInfoLog",
    
    	"glProgramUniform1i", "glProgramUniform2iv", "glProgramUniform3iv", "glProgramUniform4iv",
    	"glProgramUniform1ui", "glProgramUniform2uiv", "glProgramUniform3uiv", "glProgramUniform4uiv",
    	"glProgramUniform1f", "glProgramUniform2fv", "glProgramUniform3fv", "glProgramUniform4fv",
    	"glProgramUniform1d", "glProgramUniform2dv", "glProgramUniform3dv", "glProgramUniform4dv",
    	"glProgramUniformMatrix2fv", "glProgramUniformMatrix3fv", "glProgramUniformMatrix4fv",
    	"glProgramUniformMatrix2x3fv", "glProgramUniformMatrix2x4fv",
    	"glProgramUniformMatrix3x2fv", "glProgramUniformMatrix3x4fv",
    	"glProgramUniformMatrix4x2fv", "glProgramUniformMatrix4x3fv",
    	"glProgramUniformMatrix2dv", "glProgramUniformMatrix3dv", "glProgramUniformMatrix4dv",
    	"glProgramUniformMatrix2x3dv", "glProgramUniformMatrix2x4dv",
    	"glProgramUniformMatrix3x2dv", "glProgramUniformMatrix3x4dv",
    	"glProgramUniformMatrix4x2dv", "glProgramUniformMatrix4x3dv"};
    
    load_functions((void***)glslFunctions, glslFuncNames, sizeof(glslFunctions)/sizeof(glslFunctions[0]));
    
    ...

    Вот так я загружаю расширения OpenGL!

    Запостил: gammaker, 28 Июля 2012

    Комментарии (110) RSS

    • Только не спрашивайте, где здесь C++!
      Ответить
      • > load_functions (...,ushort count);
        > load_functions (...,sizeof(...));
        ?

        P.S. Смотри, он будет рисовать картину...уже расширил ОпэнЖоЭль.
        Ответить
        • ushort в коде инициализации - экономия на спичках...
          Ответить
          • А почему бы не экономить на спичках, если это так легко? Я пока пишу функцию сразу понимаю, что не буду загружать сразу 65536 функций. Да и вообще столько функций OpenGL не существует.
            Ответить
            • 1) Это не повысит, а снизит производительность (16-битные операции на 32-битных процах медленнее).
              2) Это не даст никакой экономии памяти.
              3) Может не хватить диапазона (в данном конкретном случае хватит, я согласен).

              Поэтому short'ы вне массивов и структур не имеют особого смысла...
              Ответить
              • >Это не повысит, а снизит производительность (16-битные операции на 32-битных процах медленнее).
                А я думал, что одинаково. 16-битные регистры же есть: ax, bx, cx, dx. Почему же они медленнее? А что насчёт 64-разрядных процессоров? Сейчас же уже все процессоры 64-разрядные, но многие программы 32-битные. 32-битные операции тоже медленные?
                Ответить
                • На интеловских процах (желающие могут посмотреть Optimization Manual) 16-битные операции медленнее 32-битных, но в 64-битном режиме скорости 32- и 64-битных равны.
                  Ответить
                  • Но так как я пишу не для интелов, а для всех, то интересует также AMD. И что насчёт 16-битных операций на ARM?
                    Ответить
                    • Насчет ARM - х.з., писал под них только на С, в архитектуре особо не копался. Но, имхо, в любом случае порезанные операции будут не быстрее чем операции с полным регистром... Исключение может быть разве что для умножений/делений да обращений к памяти.
                      Ответить
                • Ну во-первых к этим командам лишний префикс разрядности приписан - лишняя нагрузка на декодер команд.
                  Во вторых 16битные mov и ему подобные вносят ненужную зависимость от старого содержимого старших бит, что мешает процу распараллеливать операции.

                  Ну а вообще да, в основном будут с такой же скоростью работать. Вот только быстрее чем 32хбитные - никак.
                  Ответить
      • Я как раз хотел спросить
        > void load_functions(void** functions[], const char* names[], ushort count)
        Ну неужели двойная звёздочка, да ещё и с [] (хорошо хоть что не тройная) не смущает автора? Или он привычен? Я вот секунд 15 вдуплял, что там на что там на что там на что там указывает.
        Ответить
        • >Ну неужели двойная звёздочка, да ещё и с [] (хорошо хоть что не тройная) не смущает автора? Или он привычен?
          Ну я конечно хотел как-нибудь её убрать, но не придумал как. У меня такая функция единственная во всём движке. Но вроде всё понятно: массив указателей на указатели на функции.

          >Я вот секунд 15 вдуплял, что там на что там на что там на что там указывает.
          Вот и отлично. Чтобы понять мой механизм загрузки расширений нужно всего лишь каких-то 15 секунд.
          Ответить
          • Возьми и напиши свой класс функций для функций с произвольной сигнатурой. Тогда уйдет твой void**
            Ответить
            • Не люблю писать лишних классов для всяких мелочей. "Вдуплять" в ещё и в их реализацию придётся дольше, чем 15 секунд.
              Ответить
          • std::vector<void*> &functions намного проще для понимания и обработки
            Ответить
            • Вот что что, а std::vector нафиг не сдался. Или это крестотроллинг?
              Ответить
              • Тарас прошел крещение ;)
                Ответить
              • почему?
                Ответить
                • А какую полезную способность вектора ты будешь тут использовать? Возможность реаллокации? Лучше просто передать массив.
                  Ответить
                  • инкапсуляция типа данных, которая не требует писать [] хуй знает где отдельно от названия типа и не требует отдельно передавать размер массива. В нормальном языке, правда, размер передастся сам, но тут всё не так...
                    Ответить
                    • >инкапсуляция типа данных, которая не требует писать [] хуй знает где отдельно от названия типа и не требует отдельно передавать размер массива.

                      Посмотри на код ниже. Он успешно передаёт размер контейнера сам и не требует передавать его отдельно.
                      Ответить
                • template<size_t count>
                  void load_functions(const FunctionInfo (&functions)[count])
                  или
                  void load_functions(const std::array<FunctionInfo> &functions)
                  Ответить
                  • Только я опять тупанул:
                    template<size_t count> 
                    void load_functions(const std::array<FunctionInfo, count> &functions)

                    fixed
                    Ответить
                • Было бы ешё не плохо так, но кресты так не могут:
                  template<class Container>
                  void load_functions(const Container<FunctionInfo> &functions)
                  Получилось бы более обобщённо. А Ада так может?
                  Ответить
                  • Ой, что это я говорю... Могут так кресты:
                    template<template<class > class Container>
                    void load_functions(const Container<FunctionInfo> &functions)
                    Ответить
                    • Только что вспомнил.
                      Это совершенно не будет работать.
                      Для тогоже std::vector придется написать
                      template<template<class, class> class Container>
                      void load_functions(const Container<FunctionInfo> &functions)

                      А для std::set:
                      template<template<class, class, class> class Container>
                      void load_functions(const Container<FunctionInfo> &functions)

                      Для какого-то своего контейнера с каким то другим числом параметров. А потом стандарт поменяют и старый код перестанет компилироваться. Бесполезно всё это... Убогие кресты не могут в обобщенное программирование.
                      Ответить
                      • Только const для данного конкретной темы я опрометчиво поставил.
                        Ответить
                        • что-то ты загоняешься
                          template <template ...> нужен только тогда, когда код внутри шаблона собирается инстанциировать шаблонный класс несколько раз и по-разному
                          если ожидать Container<FunctionInfo> (т.е. тебе нужна только 1 версия), то и ожидай уже полностью инстанциированный тип:
                          template <class Container>
                          void load_smth(Container & c) {
                              c.push_back(foo); // будет ошибка компиляции, если у c нет метода push_back или если нельзя в него засунуть foo
                          }
                          Ответить
                          • >если нельзя в него засунуть foo
                            Опасно это. По тихому преобразоваться тип может. Например, foo - указатель, а Container - контейнер boolов. К тому же некоторые питушки иногда создают свои операторы приведения типов. Вообщем не вариант с точки зрения обобщения. Нужна надежная проверка типа в месте использования функции.

                            Да и вообще показывать на ошибку вызова функции не в месте вызова функции, а в глубине библиотеки после цепочки вызова шаблонных функций - моветон.
                            Ответить
                            • если контейнер <bool>, или операторы приведения типов, то при определении Container<bool> & arg или Container & получится ровно одинаковый эффект, не находишь?
                              ну а про ошибку в месте вызова функции - притянуто за уши

                              писать template <template ...> ради кода выше - говнокод, как раз именно потому, что лишняя работа, которая серьезно сужает применимость
                              Ответить
                  • Может, может...
                    Ответить
                    • Так как я написал в том посте - не могут.

                      ____________________
                      Отредактировал пост:
                      ЗЫ: А вы про Аду... Ок
                      Ответить
                      • Да, надо только явно написать, какие операции от контейнера нужны и какие методы эти операции реализуют.
                        Ответить
                    • что то меня гложут сомнения, Тарас
                      http://en.wikibooks.org/wiki/Ada_Programming/Generics#Generic_instances_of_other_generic_packages

                      тут написано, что генерик использует параметр P1 как другой генерик с известным уже именем Q, и задает ему либо все параметры, либо использует все по умолчанию
                      т.е. это примерно как использовать std::vector<mytype, std::allocator<mytype> >, а не Container<mytype>
                      вот такой код на Аде можно написать?
                      template <template <class, class> class Container = std::vector>
                      void dosmth() { Container<int> cont1; Container<double> cont2; ... }
                      
                      dosmth<std::vector>();
                      dosmth<std::list>();
                      Ответить
                      • >что то меня гложут сомнения, Тарас
                        Тарас молчит, а значит его тоже гложут сомнения.
                        Ответить
                      • ээ не знаю, может там можно как-то шаблонный пакет в параметрах шаблона задавать
                        я эту фичу не пользовал, что умеют пакеты в параметрах шаблона - не знаю.
                        Если что, можно тупо так:
                        dosmth<std::vector<int>, std::vector<double>>();
                        Ответить
                        • так не интересно
                          хотя бы в вот такой паттерн ада может?
                          (это один из обходов ситуации с template <template ...>)
                          http://ideone.com/Pxlpt
                          Ответить
                          • >St6vectorIiSaIiEE
                            >St3setIiSt4lessIiESaIiEE
                            can not into деманглинг, братюнь?
                            Ответить
                            • про деманглинг - это к создателям гцц
                              в студии тот же код выводит сразу нормально
                              105
                              class std::vector<int,class std::allocator<int> >
                              0
                              class std::set<int,struct std::less<int>,class std::allocator<int> >

                              интернет подсказывает, что в гцц есть abi::__cxa_demangle - лишние телодвижения
                              Ответить
                          • Кстати, а для чего Y::template apply<Z>::perform здесь template? Я понимаю, что по стандарту не скомпилируется, но какую неоднозначность здесь убирают?
                            Ответить
                            • показывают, что apply - шаблон, а не нечто, имеющее operator < к аргументу Z
                              в студии, где инстанциирование шаблона не 2х этапное, как требует стандарт, как раз template внутри можно не писать
                              Ответить
            • Все ещё пишешь на MS VC 6.0?
              Ответить
    • Если не секрет, чем не устроил GLEW?
      Ответить
      • Не знаю, я им не пользовался. Пользовался когда-то glee, но он замедлял компиляцию, и из-за него исполняемый файл разрастался. Тогда я решил загружать их сам.
        Ответить
      • Посмотрел сейчас на glew. Похоже, что не лучше glee. Хоть на говнокод выкладывай.
        И ещё я вспомнил, почему я решил сам загружать расширения: я пытаюсь загружать сначала функционал ядра, но если он не поддерживается, то загружаю аналогичное расширение на место тех же функций для совместимости. А в библиотеках типа glew они загружаются отдельно.
        Ответить
    • Гавно то в чем? Вроде все так декларативненько...
      Ответить
      • Ну например void***. А если что-то в массивах не совпадёт, могут начаться неприятные вещи. Хотя конечно они приведут к крешу и быстро исправятся.
        Да и просто так, выложил, потому что нигде подобного не видел. Везде загружают функции по одной с кастами.
        Ответить
        • Можно вот так попробовать, чтобы не терять синхронизации между массивов:
          struct FunctionInfo
          {
              void **function;
              const char *name;
          };
          
          #define FUNCTION(name) { (void**)&name, #name }
          
          FunctionInfo shader_functions[] = {
               FUNCTION(glCreateShader),
               FUNCTION(glShaderSource),
               FUNCTION(glCompileShader),
               /* ... */
          };
          
          void load_functions(FunctionInfo *functions, int count)
          {
              for(int i=0; i<count; i++)
                  *(functions[i].function) = wglGetProcAddress(functions[i].name);
          }
          
          load_functions(shader_functions, sizeof(shader_functions)/sizeof(FunctionInfo));
          Ответить
          • О, спасибо за идею, буду переделывать! Я и не думал, что govnokod.ru может быть полезен.
            Ответить
          • А чего используете void**, a не void*?
            Ответить
            • Потому что здесь нужен указатель на указатель на функцию (чтобы заполнять указатель на функцию полученным из wglGetProcAddress).
              Ответить
          • template<size_t count>
            void load_functions(FunctionInfo (&functions)[count])
            Ответить
            • А еще можно извратиться с boost::function и запилить нечто в духе
              EXT_FUNCTION(GLint (), glCreateShader);
              ...
              GLintx = glCreateShader();

              чтобы она в конструкторе сама дергала wglGetProcAddress() (если, конечно, его можно вызывать до вызова main())

              FIX: макрос вместо функции, т.к. надо имя функции передавать в wglGetProcAddress.
              Ответить
              • >А еще можно извратиться с boost::function
                А пример можете?
                Ответить
                • http://liveworkspace.org/code/39240d086ca8b581b91544de742605ee

                  WARNING. Я не помню, можно ли вызывать wglGetProcAddress до main(), и какие инициализации надо провести перед его вызовом. Поэтому этот код лучше не юзать в продакшене.

                  P.S. Зато тут не нужны кодогенераторы, функция описывается 1 раз в одной точке...
                  Ответить
                  • >WARNING. Я не помню, можно ли вызывать wglGetProcAddress до main(), и какие инициализации надо провести перед его вызовом. Поэтому этот код лучше не юзать в продакшене.
                    Нельзя. Тем более, что ещё нужно сначала инициализировать контекст OpenGL. Без него будет всегда возвращаться нулевой указатель.
                    Ответить
                    • http://liveworkspace.org/code/5e050f239eda17e52e5509a0a1b5b854

                      Вот такой вот говнокодик, поддерживающий отложенную загрузку. Вам скорее всего не подойдет из-за буста и требуемых особенностей загрузки... Но пусть лежит тут как proof-of-concept ;)

                      P.S. Торопился, поэтому смотрится как говно.
                      Ответить
                      • P.P.S. Можно попробовать передавать в конструктор не одно имя, а список имен, которые будут резольвиться через wglGetProcAddress пока он не вернет не NULL. Вроде как раз то что нужно.

                        Эх, ладно, ни к чему все это...
                        Ответить
                      • >Вам скорее всего не подойдет из-за буста
                        Лол. std::function давно уже в стандарте. Его и используй.
                        Ответить
                        • Ага... в стандарте с++11.
                          Ответить
                          • Ну gammaker вроде на гамнакоде говорил, что пишет в 2011 студии. Он же не тарас.
                            Ответить
                            • В 2010-й. Но STL не использую. У меня всё своё.
                              Ответить
                              • Что? Уже и std::function свой написал?
                                Ответить
                                • Нет, мне указателей на функции вполне хватает. Писал только то, что нужно.
                                  Ответить
                                  • >указателей на функции вполне хватает

                                    А как вы обходитесь без лямбд с замыканиями, без каррирования и объектов первого класса? Это же так способствует надежности, декларативности и обобщенности.
                                    Ответить
                                    • Это могло бы пригодиться только для оконных приложений. Я когда-то велосипедил свой Windows Forms, но так и не реализовал, потому что указателей на функции более или менее хватало. А сейчас я готовлю к переходу на C#, и там уже всё есть.

                                      Так что я выкладываю свои последние говнокоды в разделе C++...
                                      Ответить
                                      • >Это могло бы пригодиться только для оконных приложений.
                                        Для Higher Order Functions это нужно.
                                        Ответить
                  • Лол. У boost::function нет виртуального деструктора
                    Ответить
                    • Хм. А как это повлияет на работу кода? Разрушается объект здесь деструктором самого шаблона без виртуального вызова.

                      Помешать отсутствие виртуального деструктора может разве что так: кастануть объект в boost::function<T*>*, а потом сделать ему delete, но зачем...
                      Ответить
                    • P.S. Не на тот код посмотрел. В коде, к которому относится ваш комментарий, вообще виртуальных методов нет. И виртуальный деструктор там не нужен. Ни у шаблона, ни у boost::function.
                      Ответить
                  • wglGetProcAddress до main вызывать можно, только инициализируй GL до вызова wglGetProcAddress
                    Для этого можно написать обертку над wglGetProcAddress, которая будет инициализировать GL при первом вызове, если она ещё не инициализирована.
                    Ответить
          • Задача в том что бы не перечислять в ручную.
            Внешний скрипт коллектор-кодогенератор перед компиляцией?
            Ответить
            • GLEW, чтобы не писать велосипедогенераторов ;)
              Там почти весь исходник сгенерен из спецификаций расширений OpenGL.
              Ответить
              • Ну это понятно.
                Интересен уже общий случай с подобной инициализацией.
                Ответить
              • >чтобы не писать велосипедогенераторов
                Пых или питон же
                Ответить
              • Для самого glew'а неплохо бы написать генератор, преобразующий его в такой краткий вид. А то наговнокодят там что-то вроде
                #define glGenerateTextureMipmapEXT GLEW_GET_FUN(__glewGenerateTextureMipmap EXT)
                Я не понимаю, зачем это сделали? Для ленивой инициализации что ли? А IDE даже подсказок не отображает.
                Ответить
          • Нет, оказалось не всё так просто. К сожалению, мне этот способ не подошёл, потому что я загружаю сначала ядро, а если оно не поддерживается, то уже расширения, а имена функций могут отличаться не только постфиксами, но и самими названиями. Поэтому строки и названия моих функций будут отличаться.
            Ответить
            • http://www.gamedev.ru/pages/folder/OpenGL_Extensions
              А так сойдет?
              Ответить
              • Зачем мне этот дедовский способ загрузки расширений? Мне выложенный мной говнокод больше всего подходит.
                Ответить
                • Декларативней же:
                  init(glActiveTextureARB) &&
                  init(glClientActiveTextureARB) &&
                  init(glMultiTexCoord2fARB);

                  Но, как говориться: хозяин - барин.
                  Ответить
                  • Куча вызовов функции увеличит размер исполняемых файлов. Тем более, что, как я уже и сказал, имя указателя на функцию и импортируемая функция могут не совпадать. Этот говнокод - только маленькая часть кода, в которой они совпадают.
                    Ответить
                    • И ты ещё на C# хочешь пересесть?
                      Ответить
                      • А C# тут при чём? Работа с OpenGL останется на C++, а C# будет импортировать эти функции.
                        Ответить
                        • > Куча вызовов функции увеличит размер исполняемых файлов.
                          > C# будет импортировать эти функции.
                          И ты, после упоминания C#, пытаешься упоминать, что заботишься о размере файлов?
                          Ответить
                          • Хех. Напомнило другую историю:
                            Пхпешник и экономия на спичках
                            Ответить
                            • >Пхпешник и экономия на спичках
                              про зажигалку?
                              Ответить
                          • На C# вполне компактные программы получаются. Даже меньше, чем на C++. А .NET Framework 2.0, под который я буду писать, есть практически везде. А малый процент XP'шников и линуксоидов скачают его(или Mono), если у них нет. А новее мне и не надо. Тем более я смогу выкинуть кучу своих велосипедов, типа строк и массивов, которые в .NET уже есть.
                            Ответить
                            • Игрушка - это же не только исполняемый файл... Это модели, это горы текстур, это уровни и скрипты к ним, это музыка и звуковые эффекты...

                              Это я к чему - а к тому, что размер исполняемого файла важен только для игрушек уровня сапера, в которых ресурсов раз два и обчелся. И если эти ресурсы, которые кстати плохо жмутся, в отличие от экзешника, весят около 30 метров, то всем пофиг на дополнительный метр, на которые может вырасти исполняемый файл пожатый инсталлятором...
                              Ответить
                              • Я планирую сделать в движке процедурные текстуры, модели и звуки. Простенькие текстуры уже можно делать на шейдерах. Может быть сделаю своего .kkrieger'а на шарпе.
                                Ответить
                                • а точно тогда в 96 кб уложишся? Там одни обьявления к рантаймовой библиотеке половину всего сожрут.
                                  Ответить
                                  • Я как-то пробовал на шарпе сделать GUI'шную программку. Она занимала около 50 КБ, хотя на MFC она заняла бы не меньше 2 МБ. А на плюсах со сжатием exe'шника UPX'ом движок в 50 КБ умещается.
                                    Да и не ставил я особенно цель уложиться в 96 КБ. Просто стремлюсь сделать игру как можно меньше, особенно не жертвуя удобством разработки.
                                    Ответить
                            • >>А .NET Framework 2.0, под который я буду писать, есть практически везде.
                              Это только тебе так кажется.

                              >>А малый процент XP'шников и линуксоидов скачают его(или Mono), если у них нет.
                              >>ко-ко-ко
                              Скачают. Ага. Иди-ка ты нахуй.
                              Вот сраная джаба есть везде, это да.
                              Ответить
                              • >Это только тебе так кажется.
                                Больше половины пользователей пересели на семёрку. У многих XP'шников, даже мало разбирающихся в компьютерах, я видел установленный .NET Framework 2.0. А когда я допишу, XP'шников ещё меньше останется.

                                >Скачают. Ага.
                                Зато кроссплатформенно. У меня шарповые экзешники даже на телефоне через Mono запускаются без перекомпиляции.
                                Ответить
                                • >>Зато кроссплатформенно
                                  Еще как!
                                  http://govnokod.ru/10050
                                  Ответить
                                  • На C++ написать некроссплатформенный код в разы проще. А на шарпе надо постараться.
                                    А так как даже на андроидах уже многие игры занимают по 500 МБ, то Mono за 100 МБ не так уж сложно скачать.
                                    Ответить
                                    • Я не говорил ни слова о C++
                                      Но в спойлере написал про убогую джабу.
                                      http://govnokod.ru/11487#comment149085
                                      Но даже на ней иногда бывают серъезные траблы с "кроссплатформенностью".
                                      По крайней мере в сане старались.
                                      Ответить
                            • >>малый процент XP'шников и линуксоидов
                              Первая сцылка в гугли
                              http://en.wikipedia.org/wiki/Usage_share_of_operating_systems

                              И это еще самый благоприятный прогноз, обычно XP оценивают около 40%.
                              Так что нахуй.
                              Ответить
            • Запости что-ли что у тебя там получилось после сусанинских подсказок.
              Ответить
              • Ничего нового. Я всё обратно вернул.
                Ответить
                • template<size_t count>
                  void load_functions(FunctionInfo (&functions)[count])

                  А это тебе чем не понравилось то? Все же меньше вероятность ошибки.
                  Да это:
                  struct FunctionInfo
                  {
                      void **function;
                      const char *name;
                  };
                  Ответить
                  • Я же говорю, что у указателя на функцию и строки с именем функции OpenGL могут отличаться имена. Движок сначала загружает одноимённые функции, если не получается, то их ARB и EXT варианты. Поэтому одному набору указателей на функции могут соответствовать несколько наборов строк (прибавлять ARB и EXT не всегда верно).
                    Ответить
                    • А чего про первый пункт не отвечаешь?
                      template<size_t count>
                      void load_functions(void** (&functions)[count])
                      Почему бы это не применить?
                      Ответить
                      • template<size_t count>
                        void load_functions(void** (&functions)[count], const char* (&names)[count]);

                        Это конечно можно и использовать, но load_functions я вызываю достаточно редко, чтобы обойтись. А я предпочитаю не использовать шаблоны, когда они не очень нужны.
                        Ответить

    Добавить комментарий